Android輸入子系統之啓動過程分析

Android輸入子系統之啓動過程分析

平臺:Android6.0
爲了使整個流程更清晰,函數的代碼只保留跟本文分析相關的部分,並且將一些錯誤判斷相關的代碼也去掉了,如有興趣,可以查閱源碼。

Android的輸入子系統是在InputManagerService中啓動的,而InputManagerService是在system_server中啓動的。我們先看下整個啓動過程的序列圖,然後根據序列圖來一步步分析。

InputManagerService啓動過程

Step 1. SystemServer.startOtherServices

函數定義在frameworks/base/services/java/com/android/server/SystemServer.java中

//啓動核心服務
private void startCoreServices() {
}

//啓動其他的服務
private void startOtherServices() {
    //初始化一個InputManagerService對象
    inputManager = new InputManagerService(context);
    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);

    inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
    inputManager.start();

}

在SystemServer中先構造了一個InputManagerService對象和一個WindowManagerService對象,然後將InputManagerService對象傳給WindowManagerService對象,WindowManagerService中初始化了一個InputMonitor對象,調用InputManagerService.setWindowManagerCallbacks函數將InputMonitor傳進去,後面native層回調時會調用到該InputMonitor對象。

Step 2. InputManagerService.init

InputManagerService.java的構造函數定義在
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

public class InputManagerService {
    public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
        //調用nativeInit來執行C++層的初始化操作
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }
}

構造函數調用nativeInit來執行C++層的初始化操作

Step 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);
    //構造一個NativeInputManagera對象
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

這個函數主要作用是創建一個NativeInputManager實例,並將其作爲返回值保存在InputManagerService.java中的mPtr字段中。

Step 4. NativeInputManager.init

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) {
    //構造一個EventHub對象,最原始的輸入事件都是通過它收集並且粗加工然後給到InputReader對象
    sp<EventHub> eventHub = new EventHub();
    //構造一個InputManager對象
    mInputManager = new InputManager(eventHub, this, this);
}

NativeInputManager構造函數中創建了一個EventHub實例,並且將這個實例作爲參數來創建一個InputManager對象,這個對象會做一些初始化的操作。

Step 5. InputManager.init

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中讀取鍵盤事件。

Step 6. InputManager.initialize

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

這裏創建了一個InputReaderThread和InputDispatcherThread對象,前面構造函數中創建的InputReader實際上是通過InputReaderThread來讀取鍵盤事件,而InputDispatcher實際通過InputDispatcherThread來分發鍵盤事件

Step 7. InputManagerService.start

InputManagerService.java中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層啓動

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

實際調用了InputManager的start函數

Step 9. InputManager.start

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,該函數就會循環執行。

Step 10. InputDispatcherThread.threadLoop

該函數定義在frameworks/native/services/inputflinger/InputDispatcher.cpp 中

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

這裏調用前面在Step 5中創建的實例InputDispatcher的dispatchOnce函數進行一次按鍵分發

Step 11. InputDispatcher.dispatchOnce

這個函數定義在frameworks/native/services/inputflinger/InputDispatcher.cpp 中

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();

        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        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機制,後續再研究

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