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

来源:互联网 发布:阿里云服务器登录密码 编辑:程序博客网 时间:2024/05/17 00:54

Linux 3.10Android 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 && errno == ENODEV)) {                    // Device was removed before INotify noticed.                    ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d "                            "capacity: %d errno: %d)\n",                            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\n", event->code);ALOGW("getEvents, value=%d\n", 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\n", 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\n", mPendingEventIndex);ALOGW("mPendingEventCount=%d\n", 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)\n", errno);                usleep(100000);            }        } else {            // Some events occurred.            mPendingEventCount = size_t(pollResult);ALOGW("getEvents: mPendingEventCount=%d\n", mPendingEventCount);        }    }ALOGI("getEvents, exit.");    // All done, return the number of events we read.    return event - buffer;}


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

// 开机EventHub扫描设备logI/EventHub(  523): getEvents, enter.I/EventHub(  523): getEvents, mNeedToScanDevices.I/EventHub(  523): Open device from method scanDirLockedI/EventHub(  523): Opening device: /dev/input/event0D/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 scanDirLockedI/EventHub(  523): Opening device: /dev/input/event1D/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=trueI/EventHub(  523): Open device from method scanDirLockedI/EventHub(  523): Opening device: /dev/input/event2D/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 implementedI/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=trueW/EventHub(  523): getEvents, Reporting device opened: id=-1, name=<virtual>W/EventHub(  523): getEvents, Reporting device opened: id=3, name=/dev/input/event2W/EventHub(  523): getEvents, Reporting device opened: id=2, name=/dev/input/event1W/EventHub(  523): getEvents, mNeedToSendFinishedDeviceScan.W/EventHub(  523): getEvents: before while, mPendingEventIndex=0W/EventHub(  523): mPendingEventIndex=0W/EventHub(  523): mPendingEventCount=0I/EventHub(  523): getEvents, exit.

按下PowerKey点亮屏幕log

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

三、Input设备open流程

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

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

EventHub.cpp (frameworks\base\services\input)static const char *DEVICE_PATH = "/dev/input";void EventHub::scanDevicesLocked() {    status_t res = scanDirLocked(DEVICE_PATH);}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] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0')))            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\n", devicePath, strerror(errno));    } else {        buffer[sizeof(buffer) - 1] = '\0';        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\n", 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\n", devicePath, strerror(errno));    } else {        buffer[sizeof(buffer) - 1] = '\0';        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\n", devicePath, strerror(errno));    } else {        buffer[sizeof(buffer) - 1] = '\0';        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 (frameworks\base\services\input),若不属于定义中的任意一种,// 则不理会它    // 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 (frameworks\base\services\input),// 若不属于定义中的任意一种,则不理会它。// 对于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: 用户空间的输入子系统

0 0