AndroidFramework学习(五)input子系统之 EvenHub

it2025-03-19  20

AndroidFramework学习(五)input子系统之 EvenHub

auther: 朱红喜 date: 2020-10-21 version: android 8.1

Android Framework input子系统分析一 事件处理的起点 Android Framework input子系统分析二 服务端之事件收集者EventHub Android Framework input子系统分析三 服务端之事件解析者InputReader Android Framework input子系统分析四 服务端之事件分发者InputDispatcher Android Framework input子系统分析四 应用端事件处理

一、承接上文
上一篇文章分析到了InputManager里启动分别DispatcherThread,ReaderThread两个线程。我们这次要分析EventHub是如何从底层收集输入事件的,从之前的分析我们知道,InputReader负责解析EventHub收集到的输入事件信息的,所以我们应该从InputReader线程这里开始跟踪。 frameworks\native\services\inputflinger\InputManager.cpp status_t InputManager::start() { status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputDispatcher thread due to error %d.", result); return result; } result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputReader thread due to error %d.", result); mDispatcherThread->requestExit(); return result; } return OK; }

InputReaderThread的定义,我们看到他的线程运行体threadLoop()

frameworks\native\services\inputflinger\InputReader.h /* Reads raw events from the event hub and processes them, endlessly. */ class InputReaderThread : public Thread { public: explicit InputReaderThread(const sp<InputReaderInterface>& reader); virtual ~InputReaderThread(); private: sp<InputReaderInterface> mReader; virtual bool threadLoop(); }; frameworks\native\services\inputflinger\InputReader.cpp // --- InputReaderThread --- InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) : Thread(/*canCallJava*/ true), mReader(reader) { } InputReaderThread::~InputReaderThread() { } bool InputReaderThread::threadLoop() { mReader->loopOnce(); return true; } ....

线程方法中调用了InputReader的loopOnce()方法,继续进去看看

frameworks\native\services\inputflinger\InputReader.cpp void InputReader::loopOnce() { int32_t oldGeneration; int32_t timeoutMillis; bool inputDevicesChanged = false; Vector<InputDeviceInfo> inputDevices; { // acquire lock AutoMutex _l(mLock); oldGeneration = mGeneration; timeoutMillis = -1; uint32_t changes = mConfigurationChangesToRefresh; if (changes) { mConfigurationChangesToRefresh = 0; timeoutMillis = 0; refreshConfigurationLocked(changes); } else if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); } } // release lock size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); //从EventHub获取event { // acquire lock AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); if (count) { processEventsLocked(mEventBuffer, count); } if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (now >= mNextTimeout) { #if DEBUG_RAW_EVENTS ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); #endif mNextTimeout = LLONG_MAX; timeoutExpiredLocked(now); } } if (oldGeneration != mGeneration) { inputDevicesChanged = true; getInputDevicesLocked(inputDevices); } } // release lock // Send out a message that the describes the changed input devices. if (inputDevicesChanged) { mPolicy->notifyInputDevicesChanged(inputDevices); //通知输入事件已经变化 } // Flush queued events out to the listener. // This must happen outside of the lock because the listener could potentially call // back into the InputReader's methods, such as getScanCodeState, or become blocked // on another thread similarly waiting to acquire the InputReader lock thereby // resulting in a deadlock. This situation is actually quite plausible because the // listener is actually the input dispatcher, which calls into the window manager, // which occasionally calls into the input reader. //将事件队列添加到监听器,这个监听器实际上就是input dispatcher,这里必须运行在锁之外,避免因为回调InputReader方法获取锁时引起死锁,因为input dispatcher这个角色会在window manager和InputReader之间调用。 mQueuedListener->flush(); }

重点关注mEventHub->getEvents()方法,这里会调用EventHub的方法,正式进入EventHub地盘,先看看它的构造函数

frameworks\native\services\inputflinger\EventHub.cpp EventHub::EventHub(void) : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(), mOpeningDevices(0), mClosingDevices(0), mNeedToSendFinishedDeviceScan(false), mNeedToReopenDevices(false), mNeedToScanDevices(true), mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); mEpollFd = epoll_create(EPOLL_SIZE_HINT); mINotifyFd = inotify_init(); int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = EPOLL_ID_INOTIFY; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); int wakeFds[2]; result = pipe(wakeFds); ... mWakeReadPipeFd = wakeFds[0]; mWakeWritePipeFd = wakeFds[1]; result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); eventItem.data.u32 = EPOLL_ID_WAKE; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); .... }

首先得知道什么是epoll和INotify传送门,epoll是基于事件驱动的I/O方式, inotify是一个内核用于通知用户空间程序文件系统变化的机制。从上面可以知道主要做了这几件事:

通过epoll_create()创建 EpollFd文件描述符通过inotify_init()创建INotifyFd文件描述符通过inotify_add_watch(),添加对DEVICE_PATH =/dev/input的监听通过epoll_ctl(), 将mINotifyFd添加到Epoll监听中将EPOLL_ID_WAKE,用于通知唤醒创建一个管道,并将管道的读端加入到epoll的监控中

看完构造函数,我们看它真正干活的getEvent()方法

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; + for(;;){... // All done, return the number of events we read. return event - buffer; }

这个方法非常长,先折叠起来看下主要的属性,readBuffer是内核input_event数组,event指向RawEvent数组下个可用的地址,capacity表示input_event数组的剩余容量,awoken表示是否通过写入管道唤醒阻塞的epoll_wait(与构造方法呼应了)。随后进入一个死循环。

源码看的有点不懂,未完待续

二、分析
三、总结
四、参考文章
最新回复(0)