InputManagerService(输入办理服务)简称IMS,在安卓体系中担任它办理整个体系的输入部分,包括键盘、鼠标、触摸屏等等,它与WindowManager密切相关,IMS整体发动过程和重要方法如下图所示,本章将结合安卓11源码整理IMS的发动流程。

深入理解Android Framework(十一)Framework重要服务之InputManagerService(一) 启动流程

1、发动IMS服务

IMS发动流程坐落frameworks/base/services/java/com/android/server/SystemServer.java,相关代码如下:

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ...
    // 开始发动IMS
    t.traceBegin("StartInputManagerService");
    inputManager = new InputManagerService(context);
    t.traceEnd();
    ...
    // 增加inputManager服务
    ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
        /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
    ...
    // 发动InputManager
    t.traceBegin("StartInputManager");
    inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
    inputManager.start();
    t.traceEnd();
}

2、IMS发动流程

IMS在SystemServer.java中被发动后,会前往 frameworks/base/services/core/java/com/android/server/input/InputManagerService.java 中持续其发动流程,IMS的发动过程如下:

public InputManagerService(Context context) {
    this.mContext = context;
    // 将InputManager参加"android.display"线程
    this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
    mStaticAssociations = loadStaticInputPortAssociations();
    mUseDevInputEventForAudioJack =
            context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
    Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
            + mUseDevInputEventForAudioJack);
    // 初始化native层InputManager
    mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    String doubleTouchGestureEnablePath = context.getResources().getString(
            R.string.config_doubleTouchGestureEnableFile);
    mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
        new File(doubleTouchGestureEnablePath);
    // 注册本地服务
    LocalServices.addService(InputManagerInternal.class, new LocalService());
}
// 设置window反应回调函数
public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
    if (mWindowManagerCallbacks != null) {
        unregisterLidSwitchCallbackInternal(mWindowManagerCallbacks);
    }
    mWindowManagerCallbacks = callbacks;
    registerLidSwitchCallbackInternal(mWindowManagerCallbacks);
}

2.1、 native层初始化

由于IMS底层都是由C++实现的,故需要对native层的IMS进行初始化,active层的IMS初始化坐落frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
        // 获取messageQueue,该messageQueue由java传入, mHandler.getLooper().getQueue()
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);   
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    // 智能指针增加引用
    im->incStrong(0);  
    // 转jlong返回
    return reinterpret_cast<jlong>(im);   
}
...
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();
    ...
    // 初始化InputManager
    InputManager* im = new InputManager(this, this);
    mInputManager = im;
    defaultServiceManager()->addService(String16("inputflinger"), im);
}

2.2、 初始化InputManager

InputManager初始化inputDispatcher和InputReader,其初始化坐落frameworks/native/services/inputflinger/InputManager.cpp:

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();
}

2.3、 发动InputManager

InputManager在Native层初始化完毕后,将由java层调用其发动流程,该流程坐落frameworks/base/services/core/java/com/android/server/input/InputManagerService.java:

public void start() {
    Slog.i(TAG, "Starting input manager");
    nativeStart(mPtr);
    // Add ourself to the Watchdog monitors.
    Watchdog.getInstance().addMonitor(this);
    ...
}

2.4、 发动native层InputManager

nativestart调用InputManager的start方法来运行线程,该部分代码坐落com_android_server_input_InputManagerService.cpp:

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    // 将jlong转为NativeInputManager指针
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    // 获取InputManager并发动
    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}
// 发动运行 InputDispatcher(InputDispatcherThread)  InputReader(InputReaderThread)线程
// frameworks/native/services/inputflinger/InputManager.cpp
status_t InputManager::start() {
    // 发动dispatcher线程
    status_t result = mDispatcher->start();
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }
    // 发动InputReader线程
    result = mReader->start();
    if (result) {
        ALOGE("Could not start InputReader due to error %d.", result);
        mDispatcher->stop();
        return result;
    }
    return OK;
}

2.5、InputDispatcher、InputReader 线程threadLoop

当native层InputManager发动InputDispatcher、InputReader线程后,这两个线程就会进入threadLoop环节,至此IMS发动完结。

// frameworks/native/services/inputflinger/InputDispatcher.cpp
bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}
// frameworks/native/services/inputflinger/InputReader.cpp
bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}

3、 总结

以上就是对IMS的发动总体流程做了大致的整理,现在总结出IMS发动流程的时序图,其中EventHub相关常识、input事情分发流程以及native层Input事情注入等重要环节将在之后的章节中重点评论。

深入理解Android Framework(十一)Framework重要服务之InputManagerService(一) 启动流程

四、参阅文章

  1. Android 输入子体系1:IMS 初始化与发动》
  2. 《Android InputManager剖析》