• 【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: 用户空间的输入子系统

  • 相关阅读:
    关于Spring的destroy-method和scope="prototype"不能共存问题
    关于引入文件名字问题
    技术学习路
    web.xml文件配置
    性能测试中的TPS与HPS
    设计模式简介
    Cause of 400 Bad Request Errors
    vim使用技巧
    如何更好地利用Pmd、Findbugs和CheckStyle分析结果
    Java基础知识
  • 原文地址:https://www.cnblogs.com/rockyching2009/p/13283693.html
Copyright © 2020-2023  润新知