Android(安卓)5.0输入系统分析之InputReader线程分析
上编分析了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线程到此分析完。
更多相关文章
- Android(安卓)RemoteCallbackList类
- android如何完全退出应用程序
- Android培训班(68)dex文件打开流程
- Android两种相机的调用方式
- Unity3d与Android的相互调用
- 关于android WebViewClient 的方法解释
- android 事件传递机制
- Android进程通信-AIDL
- android 解锁,锁屏流程