
专栏地址: https://zhuanlan.zhihu.com/p/29152319
从我个人的理解来看,Android 的 Input 系统其实是系统级的事件处理、分发框架,它需要的功能模块大致有:事件读取、事件分类、事件分发。那么我们就从整个 Input 系统的输入源入手,了解事件是如何被输入到 Input 系统中的。
在看代码前我们先想一想,如果要我们设计一个事件分发框架的输入读取模块,要考虑到哪些子模块:
那么现在我们最起码可以知道整个学习的起点了,就是 Input 系统中,负责监听的线程是谁,监听的过程中它们做了什么。在开始之前,给大家分享一张我根据本文内容画的图:

首先,有几点共识我们都可以达成:
因此对于 InputManagerService 的创建,我们可以在 SystemServer 的 startOtherServices()方法中找到,该方法做了以下事情:
SystemServer.java startOtherServices(){ …… inputManager = new InputManagerService(context); …… inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); inputManager.start(); …… } 接下来我们就逐部分学习相应的处理。
创建 InputManagerService 对象时会完成以下工作:
InputManagerService.java public InputManagerService(Context context) { this.mCOntext= context; this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack=" + mUseDevInputEventForAudioJack); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); LocalServices.addService(InputManagerInternal.class, new LocalService()); } 这里可能有人就会问了,为什么 InputManagerService 要和 DisplayThread 绑定在一起?大家不妨想想,InputEvent 无论如何被获取、归类、分发,最终还是要被处理,也就意味着最终它的处理结果都要在 UI 上体现,那么 InputManagerService 自然要选择和 UI 亲近一些的线程在一起了。
但是问题又来了,应用都是运行在自己的主线程里的,难道 InputManagerService 要一个个绑定么,还是一个个轮询?这些做法都太过低效,那换个办法,可不可以和某个管理或非常亲近所有应用 UI 的线程绑定在一起呢?
答案是什么,我在这里先不说,大家可以利用自己的知识想想。
在 nativeInit 函数中,将 Java 层的 MessageQueue 转换为 native 层的 MessageQueue,然后再取出 Looper 用于 NativeInputManager 的初始化。可见这里的重头戏就是 NativeInputManager 的创建,这个过程做了以下事情:
com_android_server_input_InputManagerService.cpp NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper), mInteractive(true) { JNIEnv* env = jniEnv(); mCOntextObj= env->NewGlobalRef(contextObj); mServiceObj = env->NewGlobalRef(serviceObj); { AutoMutex _l(mLock); mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE; mLocked.pointerSpeed = 0; mLocked.pointerGesturesEnabled = true; mLocked.showTouches = false; } mInteractive = true; sp<EventHub> eventHub = new EventHub(); mInputManager = new InputManager(eventHub, this, this); } 看到这里很多人就会想,EventHub 是什么?取英语释义来看,它的意思是事件枢纽。我们在文章开头的时候也提到过,Input 系统的事件来源于驱动 /内核,那么我们可以猜测 EventHub 是处理来自驱动 /内核的元事件的枢纽。接下来就在源码中验证我们的想法吧。
EventHub 的创建过程中做了以下事情:
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); LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); mINotifyFd = inotify_init(); int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); …… 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); …… result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); …… } 
那么这里抛出一个问题:为什么要把管道的读端注册到 epoll 中?假如 EventHub 因为 getEvents 读不到事件而阻塞在 epoll_wait()里,而我们没有绑定读端的话,我们要怎么唤醒 EventHub ?如果绑定了管道的读端,我们就可以通过向管道的写端写数据从而让 EventHub 因为得到管道写端的数据而被唤醒。
接下来继续说 InputManager 的创建,它的创建就简单多了,创建一个 InputDispatcher 对象用于分发事件,一个 InputReader 对象用于读事件并把事件交给 InputDispatcher 分发,,然后调用 initialize()初始化,其实也就是创建了 InputReaderThread 和 InputDispatcherThread。
InputManager.cpp InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize(); } void InputManager::initialize() { mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher); } InputDispatcher 和 InputReader 的创建都相对简单。InputDispatcher 会创建自己线程的 Looper,以及设置根据传入的 dispatchPolicy 设置分发规则。InputReader 则会将传入的 InputDispatcher 封装为监听对象存起来,做一些数据初始化就结束了。
至此,InputManagerService 对象的初始化就完成了,根据开头说的,接下来就会调用 InputManagerService 的 start()方法。
在 start()方法中,做了以下事情:
InputManagerService.java public void start() { Slog.i(TAG, "Starting input manager"); nativeStart(mPtr); // Add ourself to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); registerPointerSpeedSettingObserver(); registerShowTouchesSettingObserver(); registerAccessibilityLargePointerSettingObserver(); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { updatePointerSpeedFromSettings(); updateShowTouchesFromSettings(); updateAccessibilityLargePointerFromSettings(); } }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); updatePointerSpeedFromSettings(); updateShowTouchesFromSettings(); updateAccessibilityLargePointerFromSettings(); } 显而易见这里最值得关注的就是 InputManager 的 start()方法了,可惜这个方法并不值得我们如此关心,因为它做的事情很简单,就是启动 InputDispatcherThread 和 InputReaderThread 开始监听。
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 线程是怎么和 EventHub 关联起来的呢?
对于 InputReadThread:
bool InputReaderThread::threadLoop() { mReader->loopOnce(); return true; } void InputReader::loopOnce() { …… size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // acquire lock AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); if (count) { processEventsLocked(mEventBuffer, count); } …… 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); } …… mQueuedListener->flush(); } 至此,Input 进程的创建,监听线程的启动相关学习就结束了。