InputManagerService源碼研究(一)service啓動過程

本來想通過看老羅的書來學習這部分的源碼,但實際對比發現8.0的android已經和老羅那時候的很大不一樣,所以決定自己寫一下,也當做筆記.
從名字就可以知道,InputManagerService是跟輸入有關的,這不單單指鍵盤,只要是掛載在dev/input下面的設備都和它有關。

InputManagerService的啓動

InputManagerService是在SystemServer的startOtherServices中被初始化和啓動的,此方法巨長,1200多行,我這裏只貼和InputManagerService相關的部分。

private void startOtherServices() {
...
InputManagerService inputManager = null;
...
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
traceEnd();
...
wm = WindowManagerService.main(context, inputManager,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
        !mFirstBoot, mOnlyCore, new PhoneWindowManager());
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
traceEnd();
...
  traceBeginAndSlog("StartInputManager");
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
traceEnd();
...
}

可以看到,首先會調用InputManagerService的構造函數。構造函數的源碼如下:

    public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        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());
    }

主要看如下這行

mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

此行主要調用了nativeInit方法,來初始化,並返回一個指針地址,此方法的實現是在c++,如下

\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);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

這裏主要是new了一個NativeInputManager對象,此類的構造方法如下

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
...
    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}

做了兩件事:

  1. 構造了一個EventHub對象,這個EventHub會去監聽dev/input這個目錄下文件的添加和刪除,也就是輸入設備的添加和刪除,還會監聽輸入設備的輸入事件
  2. 構造一個InputManager對象,並賦值給mInputManager全局變量,這個InputManager對象的構造會使用eventhub作爲參數。

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

1.初始化了兩個對象,mDispatchermReader,分別對應類InputDispatcher和InputReader,前者的作用是向當前激活的應用窗口分發輸入事件,後者則是監控輸入設備的事件。
2. 調用initialize()方法

這個initialize()方法的源碼如下:

void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

新建了兩個分別爲InputReaderThread和InputDispatcherThread類型的線程,這裏先不研究線程的實現,先看下去。

到這裏NativeInputManager類的構造函數就跑完了,生成的實例地址賦值給了im變量,並強制轉換成jlong型的數據返回到java層的InputManagerService方法,並把返回值賦值給mPtr變量。

再回到java層的SystemServer類的startOtherServices方法:

private void startOtherServices() {
...
InputManagerService inputManager = null;
...
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
traceEnd();
...
wm = WindowManagerService.main(context, inputManager,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
        !mFirstBoot, mOnlyCore, new PhoneWindowManager());
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
traceEnd();
...
  traceBeginAndSlog("StartInputManager");
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
traceEnd();
...
}

在新建一個InputManagerService對象並將對象賦值給inputManager變量之後,會使用這個對象創建WindowManagerService,並將WindowManagerService的實力引用賦值給wm變量,接着將wminputManager註冊到ServiceManager中。
接下來會調用inputManager.start()方法,也就是啓動inputManager服務,我們看下具體源碼

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

        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);
        ....
    }

主要就是調用了nativeStart(mPtr),並加入看門狗監控,不用多說,nativeStart又是一個native方法。實現如下

\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();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

就是調用了native層InputManager的start方法,這個方法的實現如下
\frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp

status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputReader thread due to error %d.", result);

        mDispatcherThread->requestExit();
        return result;
    }

    return OK;
}

可以看到,做的事情也很簡單,就是啓動了之前新建的兩個線程。所以接下來就是看這兩個線程做了什麼。

到這裏InputManagerService就啓動完成了,可以發現主要代碼都是在native層,其實核心的部分就是啓動了兩個線程,再下一篇就學習兩個線程做了什麼事情。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章