您的位置:首页 > 移动开发 > Android开发

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

2016-12-16 13:09 330 查看

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

一、提纲挈领

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

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

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

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


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

二、处理流程



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

AutoMutex _l(mLock);

struct input_event readBuffer[bufferSize];

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

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

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

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

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

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

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

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

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

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

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

// 10、获取当前事件属于的Input设备
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && 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扫描设备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对象的时候,会扫描该目录:

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:
用户空间的输入子系统
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: