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

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

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

111.png

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事件注入等重要环节将在之后的章节中重点讨论。

112.png

四、参考文章

  1. 《Android 输入子系统1:IMS 初始化与启动》
  2. 《Android InputManager分析》



分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改