用AI赚第一桶💰低成本搭建一套AI赚钱工具,源码可二开。 广告
同以往一样,本节通过IMS的启动过程,探讨IMS的构成。上一节提到,IMS分为Java层与Native层两个部分,其启动过程是从Java部分的初始化开始,进而完成Native部分的初始化。 #### 1. IMS的诞生 同其他系统服务一样,IMS在SystemServer中的ServerThread线程中启动。 **SystemServer.java-->ServerThread.run()** ``` public void run() { ...... InputManagerService inputManager = null; ...... // **① 新建IMS对象。**注意第二个参数wmHandler,这说明IMS的一部分功能可能会在WMS的线程中完成 inputManager= new InputManagerService(context, wmHandler); // 将IMS发布给ServiceManager,以便其他人可以访问IMS提供的接口 ServiceManager.addService(Context.INPUT_SERVICE,inputManager); // 设置向WMS发起回调的callback对象 inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); // **② 正式启动IMS** inputManager.start(); ...... /* 设置IMS给DisplayManagerService。DisplayManagerService将会把屏幕的信息发送给输入 系统作为事件加工的依据。在5.2.4节将会讨论到这些信息的作用 */ display.setInputManager(inputManager); } ``` IMS的诞生分为两个阶段: - 创建新的IMS对象。 - 调用IMS对象的start()函数完成启动。 ##### (1) IMS的创建 IMS的构造函数如下: **InputManagerService.java-->InputManagerService.InputManagerService()** ``` public InputManagerService(Context context,Handler handler) { /* 使用wmHandler的Looper新建一个InputManagerHandler。InputManagerHandler将运行在 WMS的主线程中*/ this.mHandler = new InputManagerHandler(handler.getLooper()); ...... // 每一个分为Java和Native两部分的对象在创建时都会有一个nativeInput函数 mPtr =nativeInit(this, mContext, mHandler.getLooper().getQueue()); } ``` 可以看出,IMS的构造函数非常简单。看来绝大部分的初始化工作都位于Native层。参考nativeInit()函数的实现。 **com_android_server_input_InputManagerService.cpp-->nativeInit()** ``` static jint nativeInit(JNIEnv* env, jclass clazz, jobject serviceObj, jobject contextObj, jobject messageQueueObj) { sp<MessageQueue> messageQueue =android_os_MessageQueue_getMessageQueue(env, messageQueueObj); /* 新建了一个NativeInputManager对象,NativeInputManager,此对象将是Native层组件与 Java层IMS进行通信的桥梁 */ NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper()); im->incStrong(serviceObj); // 返回了NativeInputManager对象的指针给Java层的IMS,IMS将其保存在mPtr成员变量中 returnreinterpret_cast<jint>(im); } ``` nativeInit()函数创建了一个类型为NativeInputManager的对象,它是Java层与Native层互相通信的桥梁。 看下这个类的声明可以发现,它实现了InputReaderPolicyInterface与InputDispatcherPolicyInterface两个接口。这说明上一节曾经介绍过的两个重要的输入系统参与者InputReaderPolicy和InputDispatcherPolicy是由NativeInputManager实现的,然而它仅仅为两个策略提供接口实现而已,并不是策略的实际实现者。NativeInputManager通过JNI回调Java层的IMS,由它完成决策。这一小节暂不讨论其实现细节,读者只要先记住两个策略参与者的接口实现位于NativeInputManager即可。 接下来看一下NativeInputManager的创建: **com_android_server_input_InputManagerService.cpp-->NativeInputManager::NativeInputManager()** ``` NativeInputManager::NativeInputManager(jobjectcontextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper) { ...... // 出现重点了, NativeInputManager创建了EventHub sp<EventHub> eventHub = new EventHub(); // 接着创建了Native层的InputManager mInputManager = new InputManager(eventHub, this, this); } ``` 在NativeInputManager的构造函数中,创建了两个关键人物,分别是EventHub与InputManager。EventHub复杂的构造函数使其在创建后便拥有了监听设备节点的能力,这一小节中暂不讨论它的构造函数,读者仅需知道EventHub在这里初始化即可。紧接着便是InputManager的创建了,看一下其构造函数: **InputManager.cpp-->InputManager::InputManager()** ``` InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { // 创建InputDispatcher mDispatcher = new InputDispatcher(dispatcherPolicy); // 创建 InputReader mReader= new InputReader(eventHub, readerPolicy, mDispatcher); // 初始化 initialize(); } ``` 再看initialize()函数: **InputManager.cpp-->InputManager::initialize()** ``` void InputManager::initialize() { // 创建供InputReader运行的线程InputReaderThread mReaderThread = new InputReaderThread(mReader); // 创建供InputDispatcher运行的线程InputDispatcherThread mDispatcherThread = new InputDispatcherThread(mDispatcher); } ``` InputManager的构造函数也比较简洁,它创建了四个对象,分别为IMS的核心参与者InputReader与InputDispatcher,以及它们所在的线程InputReaderThread与InputDispatcherThread。注意InputManager的构造函数的参数readerPolicy与dispatcherPolicy,它们都是NativeInputManager。 至此,IMS的创建完成了。在这个过程中,输入系统的重要参与者均完成创建,并得到了如图5-2所描述的一套体系。 :-: ![](http://img.blog.csdn.net/20150814132701337?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图 5-2 IMS的结构体系 ##### (2) IMS的启动与运行 完成IMS的创建之后,ServerThread执行了InputManagerService.start()函数以启动IMS。InputManager的创建过程分别为InputReader与InputDispatcher创建了承载它们运行的线程,然而并未将这两个线程启动,因此IMS的各员大将仍处于待命状态。此时start()函数的功能就是启动这两个线程,使得InputReader于InputDispatcher开始工作。 当两个线程启动后,InputReader在其线程循环中不断地从EventHub中抽取原始输入事件,进行加工处理后将加工所得的事件放入InputDispatcher的派发发队列中。InputDispatcher则在其线程循环中将派发队列中的事件取出,查找合适的窗口,将事件写入到窗口的事件接收管道中。窗口事件接收线程的Looper从管道中将事件取出,交由事件处理函数进行事件响应。整个过程共有三个线程首尾相接,像三台水泵似的一层层地将事件交付给事件处理函数。如图5-3所示。 :-: ![](http://img.blog.csdn.net/20150814132715787?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图 5-3 三个线程,三台水泵 InputManagerService.start()函数的作用,就像为Reader线程、Dispatcher线程这两台水泵按下开关,而Looper这台水泵在窗口创建时便已经处于运行状态了。自此,输入系统动力十足地开始运转,设备节点中的输入事件将被源源不断地抽取给事件处理者。本章的主要内容便是讨论这三台水泵的工作原理。 #### 2. IMS的成员关系 根据对IMS的创建过程的分析,可以得到IMS的成员关系如图5-4所示,这幅图省略了一些非关键的引用与继承关系。 **注意** IMS内部做了很多的抽象工作,EventHub、nputReader以及InputDispatcher等实际上都继承自相应的名为XXXInterface的接口,并且仅通过接口进行相互之间的引用。鉴于这些接口各自仅有唯一的实现,为了简化叙述我们将不提及这些接口,但是读者在实际学习与研究时需要注意这一点。 :-: ![](http://img.blog.csdn.net/20150814132728051?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图 5-4 IMS的成员关系 在图5-4中,左侧部分为Reader子系统对应于图5-3中的第一台水泵,右侧部分为Dispatcher子系统,对应于图5-3中的第二台水泵。了解了IMS的成员关系后便可以开始我们的IMS深入理解之旅了!