上编分析了InputReader线程和InputDispatcher线程启动过程后,InputReader和InputDispatcher线程可以运行起来了,那么InputReader和InputDispatcher线程是如何工作?首先分析InputReader线程。
InputReader线程启动后,是从InputReader的loopOnce函数开始
void InputReader::loopOnce() {
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
processEventsLocked(mEventBuffer, count);
mQueuedListener->flush();
}
把loopOnce分3大块来分析,已在代码中注明
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
调用EventHub.cpp中的
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
for (;;) {
if (mNeedToReopenDevices) {
mNeedToReopenDevices = false;
closeAllDevicesLocked();
mNeedToScanDevices = true;
break;
}
if (mNeedToScanDevices) {
mNeedToScanDevices=true
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
}
continue;
}
if (eventItem.data.u32 == EPOLL_ID_WAKE) {
if (eventItem.events & EPOLLIN) {
ALOGV("awoken after wake()");
awoken = true;
}
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
}
int pollResult=epoll_wait(mEpollFd,mPendingEventItems,EPOLL_MAX_EVENTS, timeoutMillis);
return event - buffer;
}
进入 for (;;)后,首先调用 scanDevicesLocked(); 是调用EventHub.cpp中的scanDevicesLocked:
void EventHub::scanDevicesLocked() {
status_t res = scanDirLocked(DEVICE_PATH);
}
scanDevicesLocked函数中调用了EventHub.java中的scanDirLocked
status_t EventHub::scanDirLocked(const char *dirname)
{
dir = opendir(dirname);
while((de = readdir(dir))) {
openDeviceLocked(devname);
}
closedir(dir);
return 0;
}
opendir打开/dev/input目录,用while((de = readdir(dir)))一一读出/dev/input目录下设备节点,然后调用EventHub.cpp中的openDeviceLocked
status_t EventHub::openDeviceLocked{
int fd = open(devicePath, O_RDWR | O_CLOEXEC);
if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1)
// Get device driver version.
if(ioctl(fd, EVIOCGVERSION, &driverVersion))
// Get device identifier.
if(ioctl(fd, EVIOCGID, &inputId))
identifier.bus = inputId.bustype;
identifier.product = inputId.product;
identifier.vendor = inputId.vendor;
identifier.version = inputId.version;
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
loadConfigurationLocked(device); //idc
// Figure out the kinds of events the device reports.
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
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;
}
// Check whether this device supports the vibrator.
if (test_bit(FF_RUMBLE, device->ffBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
}
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); //key
}
// Register with epoll.
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP;
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;
}
addDeviceLocked(device);
return 0;
}
open打开/dev/input/目录下XX个节点,读取出这个设备的有用信息。比如设备版本号多少,是什么总线,产口id等等信息。然后创建一个new Device();存放fd, deviceId, devicePath, identifier信息。接下来就是调用 loadConfigurationLocked(device); //idc函数,如果是触摸屏,根据Input Driver中的名字找到相应的名字的idc文件,如果不是触摸屏,此函数没有什么作用。然后检查是哪一类设备,进行相应的设置。比如按键keyMapStatus = loadKeyMapLocked(device);完成相应的设备初始化后,调用epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)加入了epoll中,进行数据监听。最后调用addDeviceLocked(device);函数。接下来分析addDeviceLocked函数,即是调用EventHub.cpp中的addDeviceLocked函数:
void EventHub::addDeviceLocked(Device* device) {
mDevices.add(device->id, device);
device->next = mOpeningDevices;
mOpeningDevices = device;
}
把Device加入mDevices中。经过分析,清楚了scanDevicesLocked就是打开/dev/input/*下所有设备,读出相关的信息,创建一个Device存放相关信息,并检查类型设置,然后把所有设备节点的描述符加入epoll中,最后把Device加入mDevices中。
回到getEvents中scanDevicesLocked跑完后epoll_wait监听设备节点的数据,读到数据后进入while (mPendingEventIndex < mPendingEventCount) 中,然后从const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];中一一取出数据进行判断,从 Device* device = mDevices.valueAt(deviceIndex);中取出一个Device,然后把 int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;存在RawEvent中的deviceId中。
完成后返回到loopOnce中,接下来就是loopOnce中
processEventsLocked函数调用了InputReader.cpp中processEventsLocked
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count){
for (const RawEvent* rawEvent = rawEvents; count;) {
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
}
如果 if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) 不是输入事件,执行switch (rawEvent->type) ,很清楚知道是关于设备添加、删除等操作。重点就是if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) 中processEventsForDeviceLocked函数,调用InputReader.cpp中processEventsForDeviceLocked
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
InputDevice* device = mDevices.valueAt(deviceIndex);
return;
}
device->process(rawEvents, count);
}
根据deviceId从mDevices中打出InputDevice,然后调用InputDevice中process。这个InputDevice中process是哪一个?上面分析scanDevicesLocked中知道,相应类中就的有相对应的keyMap,比如是按键类,那么是调用了InputReader.cpp中的KeyboardInputMapper::process
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_KEY: {
processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
}
}
调用了InputReader.cpp中KeyboardInputMapper::processKey
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
getListener()->notifyKey(&args);
}
把keyCode、keyCode等的数据把包成一个args,最后调用getListener()->notifyKey(&args);
getListener()->notifyKey(&args);根据前面分析《 Android 5.0输入系统分析之InputReader和InputDispatcher线程启动过程》的mReader = new InputReader(eventHub, readerPolicy, mDispatcher);其别就是InputDispatcher。所以是调用了notifyKey:
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
mArgsQueue.push(new NotifyKeyArgs(*args));
}
创建一个NotifyKeyArgs加入mArgsQueue中。然后回到了loopOnce函数,最后调用了
mQueuedListener->flush();,那么就是调用flush
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
从mArgsQueue取出NotifyArgs,然后调用了NotifyArgs中的notify。就是
void NotifyKeyArgs::notify(const sp& listener) const {
listener->notifyKey(this);
}
然后调用了InputDispatcher.cpp中的notifyKey
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
KeyEvent event;
event.initialize(args->deviceId, args->source, args->action,
flags, keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, flags, keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
needWake = enqueueInboundEventLocked(newEntry);
if (needWake) {
mLooper->wake();
}
}
把数据 封成一个KeyEvent,调用了mPolicy->interceptKeyBeforeQueueing(&event, /byref/ policyFlags); 那么mPolicy又是谁?在notifyKey()函数中会新建一个KeyEvent对象并进行初始化,然后调用mPolicy的interceptKeyBeforeQueueing(mPolicy就是NativeInputManagers)
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
uint32_t& policyFlags) {
wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
keyEventObj, policyFlags);
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
}
调用了PhoneWindowManager.java中的interceptKeyBeforeQueueing函数
对KEYCODE_VOLUME_DOWN:KeyEvent.KEYCODE_VOLUME_UP:KeyEvent.KEYCODE_VOLUME_MUTE等系统按键处理,然后调handleInterceptActions函数
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
uint32_t& policyFlags) {
if (wmActions & WM_ACTION_PASS_TO_USER) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
}
}
把policyFlags |= POLICY_FLAG_PASS_TO_USER;代表传给用户的。
回到notifyKey中,创建一个KeyEntry,把NotifyKeyArgs的数据初始化了KeyEntry。然后把KeyEntry放入到enqueueInboundEventLocked中。
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
mInboundQueue.enqueueAtTail(entry);
}
把KeyEntry放入mInboundQueue队例头。数据放好后,mLooper->wake();唤醒InputDispatcher线程。InputReader线程到此分析完。