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

受不了xxxx恶心人的行为,遂搬迁至博客园。
始发:2016-12-16 13:09:58

版本信息:
Linux:3.10
Android:4.4

一、提纲挈领

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
",
                 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
",
                 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
", mPendingEventIndex);
		// 8、有事件,去处理
		// mPendingEventCount:等待处理的事件的个数
		// mPendingEventIndex:指示当前需要处理的事件
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
			ALOGW("getEvents: #1 mPendingEventIndex=%d
", 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 && errno == ENODEV)) {
                    // Device was removed before INotify noticed.
                    ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d "
                            "capacity: %d errno: %d)
",
                            device->fd, readSize, bufferSize, capacity, errno);
                    deviceChanged = true;
                    closeDeviceLocked(device);
                } else if (readSize < 0) {
                    if (errno != EAGAIN && errno != EINTR) {
                        ALOGW("could not get event (errno=%d)", errno);
                    }
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    ALOGE("could not get event (wrong size: %d)", readSize);
                } else {
					// 11、正式开始处理device设备的Input事件
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
 
					// 12、Input事件,即input_event个数
                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
                        struct input_event& iev = readBuffer[i];
                        ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",
                                device->path.string(),
                                (int) iev.time.tv_sec, (int) iev.time.tv_usec,
                                iev.type, iev.code, iev.value);
 
						// EV_MSC:其他事件,如果一个事件类型用其他EV_*无法描述时,定义为EV_MSC类型
						// 对于kernel,它为所有Input事件打上的时间戳(timestamps)比较笼统(比如仅有一个秒数);
						// 而有的设备(比如uinput设备,详见博客末尾注释“Linux uinput设备”)可能定义一个更加详尽的时间信息,
						// 比如秒、毫秒、微妙
                        if (iev.type == EV_MSC) {
                            if (iev.code == MSC_ANDROID_TIME_SEC) {
                                device->timestampOverrideSec = iev.value;
                                continue;
                            } else if (iev.code == MSC_ANDROID_TIME_USEC) {
                                device->timestampOverrideUsec = iev.value;
                                continue;
                            }
                        }
                        if (device->timestampOverrideSec || device->timestampOverrideUsec) {
                            iev.time.tv_sec = device->timestampOverrideSec;
                            iev.time.tv_usec = device->timestampOverrideUsec;
                            if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
                                device->timestampOverrideSec = 0;
                                device->timestampOverrideUsec = 0;
                            }
                            ALOGI("applied override time %d.%06d",
                                    int(iev.time.tv_sec), int(iev.time.tv_usec));
                        }
 
#ifdef HAVE_POSIX_CLOCKS
						// 使用之前read函数读出的时间值作为when成员的数值,
						// 而不是当前时间(通过systemTime(SYSTEM_TIME_MONOTONIC)函数获取的时间值)
						// 这样事件的时间信息会更加精确,因为这个时间(CLOCK_MONOTONIC)是事件产生时driver立即打上去的
                        event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
                                + nsecs_t(iev.time.tv_usec) * 1000LL;
                        ALOGI("event time %lld, now %lld", event->when, now);
 
                        // 避免kernel因时钟错误而上报一个发生在future的事件
                        if (event->when >= now + 10 * 1000000000LL) {
                            // Double-check.  Time may have moved on.
                            nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);
                            if (event->when > time) {
                                ALOGW("An input event from %s has a timestamp that appears to "
                                        "have been generated using the wrong clock source "
                                        "(expected CLOCK_MONOTONIC): "
                                        "event time %lld, current time %lld, call time %lld.  "
                                        "Using current time instead.",
                                        device->path.string(), event->when, time, now);
                                event->when = time;
                            } else {
                                ALOGV("Event time is ok but failed the fast path and required "
                                        "an extra call to systemTime: "
                                        "event time %lld, current time %lld, call time %lld.",
                                        event->when, time, now);
                            }
                        }
#else
						// 如果不支持HAVE_POSIX_CLOCKS时钟,则用当前时间作为when成员的值
                        event->when = now;
#endif
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
						ALOGW("getEvents, code=%d
", event->code);
						ALOGW("getEvents, value=%d
", event->value);
                    }
                    if (capacity == 0) {
                        // The result buffer is full.  Reset the pending event index
                        // so we will try to read the device again on the next iteration.
                        mPendingEventIndex -= 1;
						ALOGW("getEvents: #2 mPendingEventIndex=%d
", mPendingEventIndex);
                        break;
                    }
                }
            } else if (eventItem.events & EPOLLHUP) {
                ALOGI("Removing device %s due to epoll hang-up event.",
                        device->identifier.name.string());
                deviceChanged = true;
                closeDeviceLocked(device);
            } else {
                ALOGW("Received unexpected epoll event 0x%08x for device %s.",
                        eventItem.events, device->identifier.name.string());
            }
        }
 
        // readNotify() will modify the list of devices so this must be done after
        // processing all other events to ensure that we read all remaining events
        // before closing the devices.
        ALOGW("mPendingEventIndex=%d
", mPendingEventIndex);
		ALOGW("mPendingEventCount=%d
", mPendingEventCount);
        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
			ALOGW("getEvents, readNotifyLocked.");
            mPendingINotify = false;
            readNotifyLocked();
            deviceChanged = true;
        }
 
        // Report added or removed devices immediately.
        if (deviceChanged) {
            continue;
        }
 
        // Return now if we have collected any events or if we were explicitly awoken.
        if (event != buffer || awoken) {
            break;
        }
 
        // Poll for events.  Mind the wake lock dance!
		// 使用EPoll机制,等待事件到来
        // We hold a wake lock at all times except during epoll_wait().  This works due to some
        // subtle choreography.  When a device driver has pending (unread) events, it acquires
        // a kernel wake lock.  However, once the last pending event has been read, the device
        // driver will release the kernel wake lock.  To prevent the system from going to sleep
        // when this happens, the EventHub holds onto its own user wake lock while the client
        // is processing events.  Thus the system can only sleep if there are no events
        // pending or currently being processed.
        //
        // The timeout is advisory only.  If the device is asleep, it will not wake just to
        // service the timeout.
        mPendingEventIndex = 0;
 
		// 13、mLock:在处理Input事件之前,加锁;处理完成后,解锁
        mLock.unlock(); // release lock before poll, must be before release_wake_lock
		// 14、参见“休眠锁在EventHub中的生命周期”
		// 在epoll_wait()的时候释放休眠锁,这样系统才能休眠
        release_wake_lock(WAKE_LOCK_ID);
 
		// 7、等待input事件,成功时epoll_wait() 返回就绪的监测List中的Input事件个数
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
 
		// 15、在设备驱动中,如果driver有处于挂起(pending)状态的事件,它会持有kernel休眠锁阻止系统休眠;
		// 一旦事件得到处理,driver释放kernel休眠锁,系统可能进入休眠。但是!这个事件user空间还没有处理,
		// 所以我们获取一个休眠锁,阻止系统系统休眠好让我们处理事件
        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
        mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock
 
        if (pollResult == 0) {
            // Timed out.
            mPendingEventCount = 0;
            break;
        }
 
        if (pollResult < 0) {
            // An error occurred.
            mPendingEventCount = 0;
 
            // Sleep after errors to avoid locking up the system.
            // Hopefully the error is transient.
            if (errno != EINTR) {
                ALOGW("poll failed (errno=%d)
", errno);
                usleep(100000);
            }
        } else {
            // Some events occurred.
            mPendingEventCount = size_t(pollResult);
			ALOGW("getEvents: mPendingEventCount=%d
", mPendingEventCount);
        }
    }
	ALOGI("getEvents, exit.");
 
    // All done, return the number of events we read.
    return event - buffer;
}

形象莫过于log,开机EventHub扫描设备log

// 开机EventHub扫描设备log
I/EventHub(  523): getEvents, enter.
I/EventHub(  523): getEvents, mNeedToScanDevices.
I/EventHub(  523): Open device from method scanDirLocked
I/EventHub(  523): Opening device: /dev/input/event0
D/EventHub(  523): No input device configuration file found for device 'misc'.
W/EventHub(  523): Dropping device: id=1, path='/dev/input/event0', name='misc'
 
I/EventHub(  523): Open device from method scanDirLocked
I/EventHub(  523): Opening device: /dev/input/event1
D/EventHub(  523): No input device configuration file found for device 'ft5x06_ts'. --> 触摸屏设备
I/EventHub(  523): New device: id=2, fd=106, path='/dev/input/event1', name='ft5x06_ts', classes=0x14, configuration='', keyLayout='', keyCharacterMap='', builtinKeyboard=false, usingSuspendBlockIoctl=true, usingClockIoctl=true
 
I/EventHub(  523): Open device from method scanDirLocked
I/EventHub(  523): Opening device: /dev/input/event2
D/EventHub(  523): No input device configuration file found for device 'xxx-keypad'. --> 还记得《【Android休眠】之PowerKey唤醒源实现 》中驱动.name = "xxx-keypad"
W/EventHub(  523): Unable to disable kernel key repeat for /dev/input/event2: Function not implemented
I/EventHub(  523): New device: id=3, fd=107, path='/dev/input/event2', name='xxx-keypad', classes=0x1, configuration='', keyLayout='/system/usr/keylayout/xxx-keypad.kl', keyCharacterMap='/system/usr/keychars/Generic.kcm', builtinKeyboard=true, usingSuspendBlockIoctl=true, usingClockIoctl=true
 
W/EventHub(  523): getEvents, Reporting device opened: id=-1, name=<virtual>
W/EventHub(  523): getEvents, Reporting device opened: id=3, name=/dev/input/event2
W/EventHub(  523): getEvents, Reporting device opened: id=2, name=/dev/input/event1
W/EventHub(  523): getEvents, mNeedToSendFinishedDeviceScan.
W/EventHub(  523): getEvents: before while, mPendingEventIndex=0
W/EventHub(  523): mPendingEventIndex=0
W/EventHub(  523): mPendingEventCount=0
I/EventHub(  523): getEvents, exit.

按下PowerKey点亮屏幕log

// 按下PowerKey点亮屏幕log
I/EventHub(  523): getEvents, enter.
W/EventHub(  523): getEvents: before while, mPendingEventIndex=0
W/EventHub(  523): mPendingEventIndex=0
W/EventHub(  523): mPendingEventCount=0
W/EventHub(  523): getEvents: before while, mPendingEventIndex=0
W/EventHub(  523): mPendingEventIndex=0
W/EventHub(  523): mPendingEventCount=0
 
 
W/EventHub(  523): getEvents: mPendingEventCount=1 --> 有事件上来
W/EventHub(  523): getEvents: before while, mPendingEventIndex=0
W/EventHub(  523): getEvents: #1 mPendingEventIndex=1
W/EventHub(  523): /dev/input/event2 got: time=34.860046, type=1, code=116, value=1
W/EventHub(  523): event time 34860046000, now 34860404099
W/EventHub(  523): /dev/input/event2 got: time=34.860046, type=0, code=0, value=0
W/EventHub(  523): event time 34860046000, now 34860404099
W/EventHub(  523): mPendingEventIndex=1
W/EventHub(  523): mPendingEventCount=1
I/EventHub(  523): getEvents, exit.

三、Input设备open流程

Input设备节点位于"/dev/input"目录下:

Android设备在系统起来、创建EventHub对象的时候,会扫描该目录:

status_t EventHub::scanDirLocked(const char *dirname)
{
	char devname[PATH_MAX];
	char *filename;
	// 1、DIR是一个内部结构,类似于FILE,保存当前正在被读取的目录的有关信息
	DIR *dir;
	// 2、struct dirent:描述目录文件(directory file),dirent既含有目录信息,还指有目录中的具体文件的信息
	struct dirent *de;
	// 3、opendir()打开目录"/dev/input",获取指向该目录的DIR
	dir = opendir(dirname);
	if(dir == NULL)
		return -1;

	strcpy(devname, dirname);  // devname = "/dev/input"
	filename = devname + strlen(devname);
	*filename++ = '/'; // filename = '/'
	while((de = readdir(dir))) {
		if(de->d_name[0] == '.' && (de->d_name[1] == '' || (de->d_name[1] == '.' && de->d_name[2] == '')))
			continue;
		// de->d_name:路径下的文件名,比如"/dev/input/event0",d_name = "event0"
		strcpy(filename, de->d_name); // 比如:filename = "/event0", so devname = "/dev/input/event0"
		ALOGI("Open device from method scanDirLocked");
		// open打开"/dev/input/eventX"设备节点
		openDeviceLocked(devname);
	}
	closedir(dir);
	return 0;
}

open打开"/dev/input/eventX"设备节点,获取设备信息,加入到epoll的监测列表: 

status_t EventHub::openDeviceLocked(const char *devicePath) {
    char buffer[80];
 
    ALOGI("Opening device: %s", devicePath);
    int fd = open(devicePath, O_RDWR | O_CLOEXEC);
 
    InputDeviceIdentifier identifier;
 
    // 1、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] = '';
        identifier.name.setTo(buffer);
    }
 
    // 2、Check to see if the device is on our excluded list
    for (size_t i = 0; i < mExcludedDevices.size(); i++) {
        const String8& item = mExcludedDevices.itemAt(i);
        if (identifier.name == item) {
            ALOGI("ignoring event id %s driver %s
", devicePath, item.string());
            close(fd);
            return -1;
        }
    }
 
    // 3、Get device driver version.
    int driverVersion;
    ioctl(fd, EVIOCGVERSION, &driverVersion);
 
    // 4、Get device identifier.
    struct input_id inputId;
    ioctl(fd, EVIOCGID, &inputId);
	
	// 5、初始化identifier对象相应成员
    identifier.bus = inputId.bustype;
    identifier.product = inputId.product;
    identifier.vendor = inputId.vendor;
    identifier.version = inputId.version;
 
    // 6、Get device physical location.
    if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
        //fprintf(stderr, "could not get location for %s, %s
", devicePath, strerror(errno));
    } else {
        buffer[sizeof(buffer) - 1] = '';
        identifier.location.setTo(buffer);
    }
 
    // 7、Get device unique id.
    if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
        //fprintf(stderr, "could not get idstring for %s, %s
", devicePath, strerror(errno));
    } else {
        buffer[sizeof(buffer) - 1] = '';
        identifier.uniqueId.setTo(buffer);
    }
 
    // 8、初始化identifier对象相应成员
    setDescriptor(identifier);
 
    // 9、设置对该设备的访问为非阻塞模式(non-blocking)
    if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
        ALOGE("Error %d making device file descriptor non-blocking.", errno);
        close(fd);
        return -1;
    }
 
    int32_t deviceId = mNextDeviceId++;
	// 10、构建Device对象
    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
 
    // 11、加载设备的配置信息
    loadConfigurationLocked(device);
 
    // 12、获取设备可以上报的事件的类型
    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
    ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
    ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
    ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
    ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
    ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
 
	// 13、判断设备的类别,是键盘、鼠标、触摸屏等等,设备类型定义在:
	// EventHub.h (frameworksaseservicesinput),若不属于定义中的任意一种,
	// 则不理会它
 
    // See if this is a keyboard.  Ignore everything in the button range except for
    // joystick and gamepad buttons which are handled like keyboards for the most part.
    bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC))
            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),
                    sizeof_bit_array(KEY_MAX + 1));
    bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
                    sizeof_bit_array(BTN_MOUSE))
            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),
                    sizeof_bit_array(BTN_DIGI));
    if (haveKeyboardKeys || haveGamepadButtons) {
        device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
    }
 
    // See if this is a cursor device such as a trackball or mouse.
    if (test_bit(BTN_MOUSE, device->keyBitmask)
            && test_bit(REL_X, device->relBitmask)
            && test_bit(REL_Y, device->relBitmask)) {
        device->classes |= INPUT_DEVICE_CLASS_CURSOR;
    }
 
    // See if this is a touch pad.
    // Is this a new modern multi-touch driver?
    if (test_bit(ABS_MT_POSITION_X, device->absBitmask)
            && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
        // Some joysticks such as the PS3 controller report axes that conflict
        // with the ABS_MT range.  Try to confirm that the device really is
        // a touch screen.
        if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {
            device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
        }
    // Is this an old style single-touch driver?
    } else if (test_bit(BTN_TOUCH, device->keyBitmask)
            && test_bit(ABS_X, device->absBitmask)
            && test_bit(ABS_Y, device->absBitmask)) {
        device->classes |= INPUT_DEVICE_CLASS_TOUCH;
    }
 
    // See if this device is a joystick. A joystick is an input device consisting of a stick
	// that pivots on a base and reports its angle or direction to the device it is controlling.
    // Assumes that joysticks always have gamepad buttons in order to distinguish them
    // from other devices such as accelerometers that also have absolute axes.
    if (haveGamepadButtons) {
        uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
        for (int i = 0; i <= ABS_MAX; i++) {
            if (test_bit(i, device->absBitmask)
                    && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
                device->classes = assumedClasses;
                break;
            }
        }
    }
 
    // Check whether this device has switches.
    for (int i = 0; i <= SW_MAX; i++) {
        if (test_bit(i, device->swBitmask)) {
            device->classes |= INPUT_DEVICE_CLASS_SWITCH;
            break;
        }
    }
 
    // Check whether this device supports the vibrator.
    if (test_bit(FF_RUMBLE, device->ffBitmask)) {
        device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
    }
 
    // Configure virtual keys.
    if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
        // Load the virtual keys for the touch screen, if any.
        // We do this now so that we can make sure to load the keymap if necessary.
        status_t status = loadVirtualKeyMapLocked(device);
        if (!status) {
            device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
        }
    }
 
    // Load the key map.
    // We need to do this for joysticks too because the key layout may specify axes.
    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);
    }
 
    // Configure the keyboard, gamepad or virtual keyboard.
    if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
        // Register the keyboard as a built-in keyboard if it is eligible.
        if (!keyMapStatus
                && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD
                && isEligibleBuiltInKeyboard(device->identifier,
                        device->configuration, &device->keyMap)) {
            mBuiltInKeyboardId = device->id;
        }
 
        // 'Q' key support = cheap test of whether this is an alpha-capable kbd
        if (hasKeycodeLocked(device, AKEYCODE_Q)) {
            device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
        }
 
        // See if this device has a DPAD.
        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;
            }
        }
 
        // Disable kernel key repeat since we handle it ourselves
        unsigned int repeatRate[] = {0,0};
        if (ioctl(fd, EVIOCSREP, repeatRate)) {
            ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno));
        }
    }
 
    // 14、设备类型定义在:EventHub.h (frameworksaseservicesinput),
	// 若不属于定义中的任意一种,则不理会它。
	// 对于PowerKey,其类型为:INPUT_DEVICE_CLASS_KEYBOARD
    if (device->classes == 0) {
        ALOGW("Dropping device: id=%d, path='%s', name='%s'",
                deviceId, devicePath, device->identifier.name.string());
        delete device;
        return -1;
    }
 
    // Determine whether the device is external or internal.
    if (isExternalDeviceLocked(device)) {
        device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
    }
 
    if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_GAMEPAD)) {
        device->controllerNumber = getNextControllerNumberLocked(device);
    }
 
    // 15、添加到epoll的检测列表里
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = deviceId;
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
        delete device;
        return -1;
    }
 
    // Enable wake-lock behavior on kernels that support it.
    // TODO: Only need this for devices that can really wake the system.
    bool usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1);
 
    // Tell the kernel that we want to use the monotonic clock for reporting timestamps
    // associated with input events.  This is important because the input system
    // uses the timestamps extensively and assumes they were recorded using the monotonic
    // clock.
    // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock.
    int clockId = CLOCK_MONOTONIC;
    bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);
 
    ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
            "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
            "usingSuspendBlockIoctl=%s, usingClockIoctl=%s",
         deviceId, fd, devicePath, device->identifier.name.string(),
         device->classes,
         device->configurationFile.string(),
         device->keyMap.keyLayoutFile.string(),
         device->keyMap.keyCharacterMapFile.string(),
         toString(mBuiltInKeyboardId == deviceId),
         toString(usingSuspendBlockIoctl), toString(usingClockIoctl));
 
	// 若是我们在意的Input设备,则加入监测设备List
    addDeviceLocked(device);
    return 0;
}

四、休眠锁在EventHub中的生命周期

注: Linux uinput设备

我们知道,对于Input设备,流程基本就是硬件-kernel-应用,uinput作为kernel的一个模块(纯软件),allows to handle the input subsystem from user land. It can be used to create and to handle input devices from an application。详细参考资料:uinput: 用户空间的输入子系统

原文地址:https://www.cnblogs.com/rockyching2009/p/13283693.html