Input子系统框架之IMS的创建与启动

一、概述

IMS分为Java层与Native层两个部分,其启动过程是从Java部分的初始化开始,进而完成Native部分的初始化。 IMS在SystemServer.startOtherServices()方法中启动的。IMS的诞生分为两个阶段:

  • · 创建新的IMS对象。
  • 调用IMS对象的start()函数完成启动。

我们先看下整个启动过程的序列图,然后根据序列图来一步步分析。
在这里插入图片描述

二、系统启动IMS服务过程

1、 SystemServer.startOtherServices()

 [->frameworks/base/services/java/com/android/server/SystemServer.java]

 private void startOtherServices() {
 ......
 try {
     ......
       // ① 新建IMS对象。
     traceBeginAndSlog("StartInputManagerService");
     inputManager = new InputManagerService(context);
     Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

     traceBeginAndSlog("StartWindowManagerService");
     wm = WindowManagerService.main(context, inputManager,
             mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
             !mFirstBoot, mOnlyCore);
      //将WindowManagerService加入到ServiceManager中
     ServiceManager.addService(Context.WINDOW_SERVICE, wm);
     //将InputManagerService加入到ServiceManager中
     ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
     Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

     mActivityManagerService.setWindowManager(wm);
      // 设置向WMS发起回调的callback对象
     inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
     // ② 正式启动IMS
     inputManager.start();
     }
}

在SystemServer中先构造了一个InputManagerService对象和一个WindowManagerService对象,然后将InputManagerService对象传给WindowManagerService对象,WindowManagerService中初始化了一个InputMonitor对象,调用InputManagerService.setWindowManagerCallbacks函数将InputMonitor传进去,后面native层回调时会调用到该InputMonitor对象。

2、 InputManagerService()

   [->frameworks/base/services/core/java/com/android/server/input/InputManagerService.java]

    public InputManagerService(Context context) {
    this.mContext = context;
    //注意这里拿了DisplayThread的Handler,意味着IMS中的消息队列处理都是在单独的DisplayThread中进行的。
    //它是系统中共享的单例前台线程,主要用作输入输出的处理用。这样可以使用户体验敏感的处理少受其它工作的影响,减少延时。
    this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
    //调用nativeInit来执行C++层的初始化操作
    mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    LocalServices.addService(InputManagerInternal.class, new LocalService());
}

3、 InputManagerService.nativeInit()

[->frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp]

static jlong 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(0);
// 返回了NativeInputManager对象的指针给Java层的IMS,IMS将其保存在mPtr成员变量中
return reinterpret_cast<jlong>(im);
}

这个函数主要作用是创建一个NativeInputManager实例,并将其作为返回值保存在InputManagerService.java中的mPtr字段中。

4、NativeInputManager()

[->frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp]

NativeInputManager::NativeInputManager(jobject contextObj,
    jobject serviceObj, const sp<Looper>& looper) :
    mLooper(looper), mInteractive(true) {
// 出现重点了, NativeInputManager创建了EventHub
//构造一个EventHub对象,最原始的输入事件都是通过它收集并且粗加工然后给到InputReader对象
sp<EventHub> eventHub = new EventHub();
// 接着创建了Native层的InputManager
mInputManager = new InputManager(eventHub, this, this);
}

NativeInputManager构造函数中创建了一个EventHub实例(稍后会详细介绍),并且将这个实例作为参数来创建一个InputManager对象,这个对象会做一些初始化的操作。

5、InputManager()

[->frameworks/native/services/inputflinger/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();
}

这里创建了InputDispatcher对象用于分发按键给当前focus的窗口的,同时创建了一个InputReader用于从EventHub中读取事件。

6、InputManager.initialize()

[->frameworks/native/services/inputflinger/InputManager.cpp]

void InputManager::initialize() {
 // 创建供InputReader运行的线程InputReaderThread
mReaderThread = new InputReaderThread(mReader);
  // 创建供InputDispatcher运行的线程InputDispatcherThread
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

这里创建了一个InputReaderThread和InputDispatcherThread对象,前面构造函数中创建的InputReader实际上是通过InputReaderThread来读取事件,而InputDispatcher实际通过InputDispatcherThread来分发事件,至此,IMS的创建完成了。在这个过程中,输入系统的重要参与者均完成创建。

IMS的成员关系
在这里插入图片描述

三、IMS启动

IMS启动主要是将前面创建的InputReaderThread和InputDispatcherThread启动起来

1、InputManagerService.start()

[->frameworks/base/services/core/java/com/android/server/input/InputManagerService.java]

public void start() {
    Slog.i(TAG, "Starting input manager");
    nativeStart(mPtr);
    ...
}

该函数主要调用了nativeStart进入native层启动

2. InputManagerService.nativeStart()

[->frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp]

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

status_t result = im->getInputManager()->start();
}

进入native层InputManager的start函数

3、InputManager.start()

[->frameworks/native/services/inputflinger/InputManager.cpp]

status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
return OK;
}

这个函数实际启动了一个InputReaderThread和InputDispatcherThread来从读取和分发键盘消息,调用它们的run方法后,就会进入threadLoop函数中,只要threadLoop函数返回true,该函数就会循环执行。

InputReaderThread不断调用InputReader的pollOnce()->getEvents()函数来得到事件,这些事件可以是输入事件,也可以是由inotify监测到设备增减变更所触发的事件,稍后会详细介绍。

4、InputReaderThread.threadLoop()

[->frameworks/native/services/inputflinger/InputReader.cpp]

bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}

这里调用前面创建的InputReaderThread对象的loopOnce进行一次线程循环

5、InputReaderThread.loopOnce()

[->frameworks/native/services/inputflinger/InputReader.cpp]

 void InputReader::loopOnce() {
......
/* ① 通过EventHub抽取事件列表。读取的结果存储在参数mEventBuffer中,返回值表示事件的个数
   当EventHub中无事件可以抽取时,此函数的调用将会阻塞直到事件到来或者超时 */
size_tcount = mEventHub->getEvents(timeoutMillis,mEventBuffer, EVENT_BUFFER_SIZE);
{
   AutoMutex _l(mLock);
    ......
    if(count) {
       // ② 如果有抽得事件,则调用processEventsLocked()函数对事件进行加工处理
       processEventsLocked(mEventBuffer, count);
    }
    ......
}
......
/* ③ 发布事件。 processEventsLocked()函数在对事件进行加工处理之后,便将处理后的事件存储在
  mQueuedListener中。在循环的最后,通过调用flush()函数将所有事件交付给InputDispatcher */
  mQueuedListener->flush();
  }

InputReader的一次线程循环的工作思路比较清晰,一共三步:

  • 首先从EventHub中抽取未处理的事件列表。这些事件分为两类,一类是从设备节点中读取的原始输入事件,另一类则是输入设备可用性变化事件,简称为设备事件。
  • 通过processEventsLocked()对事件进行处理。对于设备事件,此函数对根据设备的可用性加载或移除设备对应的配置信息。对于原始输入事件,则在进行转译、封装与加工后将结果暂存到mQueuedListener中。
  • 所有事件处理完毕后,调用mQueuedListener.flush()将所有暂存的输入事件一次性地交付给InputDispatcher。

这便是InputReader的总体工作流程。而我们接下来将详细讨论这三步的实现。

6、InputDispatcherThread.threadLoop()

InputDisptacher的主要任务是把收到的输入事件发送到PhoneWIndowManager或App端的焦点窗口上,稍后详细介绍。

[->frameworks/native/services/inputflinger/InputDispatcher.cpp]

bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}

这里调用前面创建的InputDispatcher对象的dispatchOnce函数进行一次按键分发

7、InputDispatcher.dispatchOnce()

[->frameworks/native/services/inputflinger/InputDispatcher.cpp]

void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
    AutoMutex _l(mLock);
    mDispatcherIsAliveCondition.broadcast();
    if (!haveCommandsLocked()) {
        dispatchOnceInnerLocked(&nextWakeupTime);
    }
    if (runCommandsLockedInterruptible()) {
        nextWakeupTime = LONG_LONG_MIN;
    }
} // release lock
// Wait for callback or timeout or wake.  (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}

上述函数主要是调用dispatchOnceInnerLocked来进行一次按键分发,当没有按键消息时会走到mLooper->pollOnce(timeoutMillis);这个函数会进入睡眠状态,当有按键消息发生时该函数会返回,然后走到dispatchOnceInnerLocked函数。这里mLooper->pollOnce为何会睡眠涉及到Android的Handler机制。

四、小结:

完成IMS的创建之后,InputManagerService.start()函数以启动IMS。InputManager的创建过程分别为InputReader与InputDispatcher创建了承载它们运行的线程,然而并未将这两个线程启动,因此IMS的各员大将仍处于待命状态。此时start()函数的功能就是启动这两个线程,使得InputReader于InputDispatcher开始工作。

当两个线程启动后,InputReader在其线程循环中不断地从EventHub中抽取原始输入事件,进行加工处理后将加工所得的事件放入InputDispatcher的派发发队列中。InputDispatcher则在其线程循环中将派发队列中的事件取出,查找合适的窗口,将事件写入到窗口的事件接收管道中。窗口事件接收线程的Looper从管道中将事件取出,交由事件处理函数进行事件响应。整个过程共有三个线程首尾相接,像三台水泵似的一层层地将事件交付给事件处理函数。如下图所示。
在这里插入图片描述

InputManagerService.start()函数的作用,就像为Reader线程、Dispatcher线程这两台水泵按下开关,而Looper这台水泵在窗口创建时便已经处于运行状态了。自此,输入系统动力十足地开始运转,设备节点中的输入事件将被源源不断地抽取给事件处理者。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值