参考:《深入理解Android 卷III》
输入事件的源头是位于/dev/input/下的设备节点,而输入系统的终点是由WMS管理的某个窗口。最初的输入事件为内核生成的原始事件,而最终交付给窗口的则是KeyEvent或MotionEvent对象。因此Android输入系统的主要工作是读取设备节点中的原始事件,将其加工封装,然后派发给一个特定的窗口以及窗口中的控件。这个过程由InputManagerService系统服务为核心的多个参与者共同完成。输入系统的总体流程和参与者如图所示。
- Linux内核,接受输入设备的中断,并将原始事件的数据写入到设备节点中。
- 设备节点,作为内核与IMS的桥梁,它将原始事件的数据暴露给用户空间,以便IMS可以从中读取事件。
- InputManagerService,一个Android系统服务,它分为Java层和Native层两部分。Java层负责与WMS的通信。而Native层则是InputReader和InputDispatcher两个输入系统关键组件的运行容器。
- EventHub,直接访问所有的设备节点。并且正如其名字所描述的,它通过一个名为getEvents()的函数将所有输入系统相关的待处理的底层事件返回给使用者。这些事件包括原始输入事件、设备节点的增删等。
- InputReader,是IMS中的关键组件之一。它运行于一个独立的线程Reader线程中,通过其线程循环不断地通过getEvents()函数从EventHub中将事件取出并进行处理。然后交给InputDispatcher进行派发。
- InputDispatcher,是IMS中的另一个关键组件。它也运行于一个独立的线程中Dispatcher线程中。InputDispatcher中保管了来自WMS的所有窗口的信息,其收到来自InputReader的输入事件后,会在其保管的窗口中寻找合适的窗口,并将事件派发给此窗口。
- WMS,虽说不是输入系统中的一员,但是它却对InputDispatcher的正常工作起到了至关重要的作用。当新建窗口时,WMS为新窗口和IMS创建了事件传递所用的通道。另外,WMS还将所有窗口的信息,包括窗口的可点击区域,焦点窗口等信息,实时地更新到IMS的InputDispatcher中,使得InputDispatcher可以正确地将事件派发到指定的窗口。
以下是代码分析,建议用sourceinsight进行代码跟踪。
输入系统会创建Reader线程和Dispatcher线程
Reader线程和Dispatcher线程创建及启动过程源码分析:
SystemServer所有服务被创建的源头,同其他系统服务一样,IMS在SystemServer中被启动。
SystemServer.java (frameworks\base\services\java\com\android\server)
private void startOtherServices() {
inputManager = new InputManagerService(context); //创建InputManagerService
inputManager.start(); //启动这个服务
}
InputManagerService.java (frameworks\base\services\core\java\com\android\server\input)
public InputManagerService(Context context) {
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); //调用本地方法进行初始化
}
public void start() {
nativeStart(mPtr); //调用本地nativeStart函数
}
调用native方法,创建Reader线程和Dispatcher线程并启动
com_android_server_input_InputManagerService.cpp (frameworks\base\services\core\jni)
static jlong nativeInit {
/* 创建了一个NativeInputManager对象,此对象将是Native层组件与Java层IMS进行通信的桥梁 */
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper());
}
NativeInputManager::NativeInputManager {
//NativeInputManager创建了EventHub,EventHub复杂的构造函数使其在创建后便拥有了监听设备节点的能力(Inotify和epoll机制)
sp<EventHub> eventHub = new EventHub();
// 接着创建了Native层的InputManager
mInputManager = new InputManager(eventHub, this, this);
}
被InputManagerService的start函数所调用来启动线程。
static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();
}
InputManager统一创建并管理mReader、mReaderThread、mDispatcher、mDispatcherThread这四个实例化对象。
InputManager.cpp (frameworks\native\services\inputflinger)
class InputManager {
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
sp<InputDispatcherInterface> mDispatcher;
sp<InputDispatcherThread> mDispatcherThread;
}
/* 在InputManager中创建InputDispatcher和InputReader实例化对象 */
InputManager::InputManager {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
void InputManager::initialize() {
//创建Reader线程和Dispatcher线程
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
status_t InputManager::start() {
/* 启动ReaderThread和DispatcherThread */
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
}