亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android開發(fā)InputManagerService創(chuàng)建與啟動流程

 更新時間:2022年11月03日 09:45:14   作者:大胃粥  
這篇文章主要為大家介紹了Android開發(fā)InputManagerService創(chuàng)建與啟動流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

之前寫過幾篇關于輸入系統(tǒng)的文章,但是還沒有寫完,后來由于工作的變動,這個事情就一直耽擱了。而現(xiàn)在,在工作中,遇到輸入系統(tǒng)相關的事情也越來越多,其中有一個非常有意思的需求,因此是時候繼續(xù)分析 InputManagerService。

InputManagerService 系統(tǒng)文章,基于 Android 12 進行分析。

本文將以 IMS 簡稱 InputManagerService。

啟動流程

InputManagerService 是一個系統(tǒng)服務,啟動流程如下

// SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
            // ..
    // 1. 創(chuàng)建
    inputManager = new InputManagerService(context);
    // 注冊服務    
    ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
    // 保存 wms 的回調(diào)
    inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
    // 2. 啟動
    inputManager.start();    
    try {
        // 3. 就緒
        if (inputManagerF != null) {
            inputManagerF.systemRunning();
        }
    } catch (Throwable e) {
        reportWtf("Notifying InputManagerService running", e);
    }
    // ...
}

IMS 的啟動流程分為三步

  • 創(chuàng)建輸入系統(tǒng),建立上層與底層的映射關系。
  • 啟動輸入系統(tǒng),其實就是啟動底層輸入系統(tǒng)的幾個模塊。
  • 輸入系統(tǒng)就緒,上層會同步一些配置給底層輸入系統(tǒng)。

下面分三個模塊,分別講解這三步。

創(chuàng)建輸入系統(tǒng)

// InputManagerService.java
public InputManagerService(Context context) {
    this.mContext = context;
    this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
    // 配置為空
    mStaticAssociations = loadStaticInputPortAssociations();
    // 默認 false
    mUseDevInputEventForAudioJack =
            context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
    // 1. 底層進行初始化
    // mPtr 指向底層創(chuàng)建的 NativeInputManager 對象
    mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    // 空
    String doubleTouchGestureEnablePath = context.getResources().getString(
            R.string.config_doubleTouchGestureEnableFile);
    // null
    mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
        new File(doubleTouchGestureEnablePath);
    LocalServices.addService(InputManagerInternal.class, new LocalService());
}

IMS 構造函數(shù),主要就是調(diào)用 nativeInit() 來初始化底層輸入系統(tǒng)。

// com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    // 從Java層的MessageQueue中獲取底層映射的MessageQueue
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == nullptr) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    // 創(chuàng)建 NativeInputManager
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    // 返回指向 NativeInputManager 對象的指針
    return reinterpret_cast<jlong>(im);
}

原來底層創(chuàng)建了 NativeInputManager 對象,然后返回給上層。

但是 NativeInputManager 并不是底層輸入系統(tǒng)的服務,它只是一個連接上層輸入系統(tǒng)和底層輸入系統(tǒng)的橋梁而已。來看下它的創(chuàng)建過程

// com_android_server_input_InputManagerService.cpp
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();
    // 1.保存上層的InputManagerService對象
    mServiceObj = env->NewGlobalRef(serviceObj);
    // 2. 初始化一些參數(shù)
    {
        AutoMutex _l(mLock);
        // mLocked 的類型是 struct Locked,這里初始化了一些參數(shù)
        // 這些參數(shù)會被上層改變
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
        mLocked.pointerCapture = false;
        mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
    }
    mInteractive = true;
    // 3.創(chuàng)建并注冊服務 InputManager
    mInputManager = new InputManager(this, this);
    defaultServiceManager()->addService(String16("inputflinger"),
            mInputManager, false);
}

NativeInputManager 構造過程如下

  • 創(chuàng)建一個全局引用,并通過 mServiceObj 指向上層的 InputManagerService 對象。
  • 初始化參數(shù)。這里要注意一個結構體變量 mLocked,它的一些參數(shù)都是由上層控制的。例如,mLocked.showTouches 是由開發(fā)者選項中 "Show taps" 決定的,它的功能是在屏幕上顯示一個觸摸點。
  • 創(chuàng)建并注冊服務 InputManager。

原來,InputManager 才是底層輸入系統(tǒng)的服務,而 NativeInputManagerService 通過 mServiceObj 保存了上層 InputManagerService 引用,并且上層 InputManagerService 通過 mPtr 指向底層的 NativeInputManager。因此,我們可以判定 NativeInputManager 就是一個連接上層與底層的橋梁。

我們注意到創(chuàng)建 InputManager 使用了兩個 this 參數(shù),這里介紹下 NativeInputManager 和 InputManager 的結構圖

InputManager 構造函數(shù)需要的兩個接口正好是由 NativeInputManager 實現(xiàn)的,然而,具體使用這兩個接口的不是 InputManager,而是它的子模塊。這些子模塊都是在 InputManager 的構造函數(shù)中創(chuàng)建的

// InputManager.cpp
InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    // 1. 創(chuàng)建InputDispatcher對象,使用 InputDispatcherPolicyInterface 接口
    mDispatcher = createInputDispatcher(dispatcherPolicy);
    // 2. 創(chuàng)建InputClassifier對象,使用 InputListenerInterface
    mClassifier = new InputClassifier(mDispatcher);
    // 3. 創(chuàng)建InputReader對象,使用 InputReaderPolicyInterface 和 InputListenerInterface
    mReader = createInputReader(readerPolicy, mClassifier);
}
// InputDispatcherFactory.cpp
sp<InputDispatcherInterface> createInputDispatcher(
        const sp<InputDispatcherPolicyInterface>& policy) {
    return new android::inputdispatcher::InputDispatcher(policy);
}
// InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,
                                           const sp<InputListenerInterface>& listener) {
    return new InputReader(std::make_unique<EventHub>(), policy, listener);
}

InputManager 構造函數(shù)所使用的兩個接口,分別由 InputDispatcher 和 InputReader 所使用。因此 InputManager 向上通信的能力是由子模塊 InputDispatcher 和 InputReader 實現(xiàn)的。

InputManager 創(chuàng)建了三個模塊,InputReader、InputClassifier、InputDispatcher。 InputReader 負責從 EventHub 中獲取事件,然后把事件加工后,發(fā)送給 InputClassfier。InputClassifer 會把事件發(fā)送給 InputDispatcher,但是它會對觸摸事件進行一個分類工作。最后 InputDispatcher 對進行事件分發(fā)。

那么現(xiàn)在我們可以大致推算下輸入系統(tǒng)的關系圖,如下

這個關系圖很好的體現(xiàn)了設計模式的單一職責原則。

EventHub 其實只屬于 InputReader,因此要想解剖整個輸入系統(tǒng),我們得逐一解剖 InputReader、InputClassifier、InputDispatcher。后面的一系列的文章將逐個來剖析。

啟動輸入系統(tǒng)

// InputManagerService.java
    public void start() {
        Slog.i(TAG, "Starting input manager");
        // 1.啟動native層
        nativeStart(mPtr);
        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);
        // 2.監(jiān)聽數(shù)據(jù)庫,當值發(fā)生改變時,通過 native 層
        // 監(jiān)聽Settings.System.POINTER_SPEED,這個表示手指的速度
        registerPointerSpeedSettingObserver();
        // 監(jiān)聽Settings.System.SHOW_TOUCHES,這個表示是否在屏幕上顯示觸摸坐標
        registerShowTouchesSettingObserver();
        // 監(jiān)聽Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON
        registerAccessibilityLargePointerSettingObserver();
        // 監(jiān)聽Settings.Secure.LONG_PRESS_TIMEOUT,這個多少毫秒觸發(fā)長按事件
        registerLongPressTimeoutObserver();
        // 監(jiān)聽用戶切換
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updatePointerSpeedFromSettings();
                updateShowTouchesFromSettings();
                updateAccessibilityLargePointerFromSettings();
                updateDeepPressStatusFromSettings("user switched");
            }
        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
        // 3. 從數(shù)據(jù)庫獲取值,并傳遞給 native 層
        updatePointerSpeedFromSettings();
        updateShowTouchesFromSettings();
        updateAccessibilityLargePointerFromSettings();
        updateDeepPressStatusFromSettings("just booted");
    }

輸入系統(tǒng)的啟動過程如下

  • 啟動底層輸入系統(tǒng)。其實就是啟動剛剛說到的 InputReader, InputDispatcher。
  • 監(jiān)聽一些廣播。因為這些廣播與輸入系統(tǒng)的配置有關,當接收到這些廣播,會更新配置到底層。
  • 直接讀取配置,更新到底層輸入系統(tǒng)。

第2步和第3步,本質(zhì)上其實都是更新配置到底層,但是需要我們對 InputReader 的運行過程比較熟悉,因此這個配置更新過程,留到后面分析。

現(xiàn)在我們直接看下如何啟動底層的輸入系統(tǒng)

// com_android_server_input_InputManagerService.cpp
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    // 調(diào)用InputManager::start()
    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

通過 JNI 層的 NativeInputManager 這個橋梁來啟動 InputManager。

前面用一幅圖表明了 NativeInputManager 的橋梁作用,現(xiàn)在感受到了嗎?

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

InputManager 的啟動過程很簡單,就是直接啟動它的子模塊 InputDispatcher 和 InputReader。

InputDispatcher 和 InputReader 的啟動,都是通過 InputThread 創(chuàng)建一個線程來執(zhí)行任務。

//InputThread.cpp
InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
     : mName(name), mThreadWake(wake) {
   mThread = new InputThreadImpl(loop);
   mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
}

注意 InputThread 可不是一個線程,InputThreadImpl 才是一個線程,如下

//InputThread.cpp
class InputThreadImpl : public Thread {
public:
    explicit InputThreadImpl(std::function<void()> loop)
          : Thread(/* canCallJava */ true), mThreadLoop(loop) {}
    ~InputThreadImpl() {}
private:
    std::function<void()> mThreadLoop;
    bool threadLoop() override {
        mThreadLoop();
        return true;
    }
};

當線程啟動后,會循環(huán)調(diào)用 threadLoop(),直到這個函數(shù)返回 false。從 InputThreadImpl 的定義可以看出,threadLoop() 會一直保持循環(huán),并且每一次循環(huán),會調(diào)用一次 mThreadLoop(),而函數(shù) mThreadLoop 是由 InputReader 和 InputDispacher 在啟動時傳入

// InputReader.cpp
status_t InputReader::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    // 線程啟動后,循環(huán)調(diào)用 loopOnce()
    mThread = std::make_unique<InputThread>(
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
    return OK;
}
// InputDispatcher.cpp
status_t InputDispatcher::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    // 線程啟動后,循環(huán)調(diào)用 dispatchOnce()
    mThread = std::make_unique<InputThread>(
            "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
    return OK;
}

現(xiàn)在,我們可以明白,InputReader 啟動時,會創(chuàng)建一個線程,然后循環(huán)調(diào)用 loopOnce() 函數(shù),而 InputDispatcher 啟動時,也會創(chuàng)建一個線程,然后循環(huán)調(diào)用 dispatchOnce()。

輸入系統(tǒng)就緒

// InputManagerService.java
public void systemRunning() {
    mNotificationManager = (NotificationManager)mContext.getSystemService(
            Context.NOTIFICATION_SERVICE);
    synchronized (mLidSwitchLock) {
        mSystemReady = true;
        // Send the initial lid switch state to any callback registered before the system was
        // ready.
        int switchState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID);
        for (int i = 0; i < mLidSwitchCallbacks.size(); i++) {
            LidSwitchCallback callback = mLidSwitchCallbacks.get(i);
            callback.notifyLidSwitchChanged(0 /* whenNanos */, switchState == KEY_STATE_UP);
        }
    }
    // 監(jiān)聽廣播,通知底層加載鍵盤布局
    IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
    filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
    filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
    filter.addDataScheme("package");
    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updateKeyboardLayouts();
        }
    }, filter, null, mHandler);
    // 監(jiān)聽廣播,通知底層加載設備別名
    filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            reloadDeviceAliases();
        }
    }, filter, null, mHandler);
    // 直接通知一次底層加載鍵盤布局和加載設備別名
    mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
    mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
    if (mWiredAccessoryCallbacks != null) {
        mWiredAccessoryCallbacks.systemReady();
    }
}
private void reloadKeyboardLayouts() {
    nativeReloadKeyboardLayouts(mPtr);
}
private void reloadDeviceAliases() {
    nativeReloadDeviceAliases(mPtr);
}

無論是通知底層加載鍵盤布局,還是加載設備別名,其實都是讓底層更新配置。與前面一樣,更新配置的過程,留到后面分析。

結束

通過本文,我們能大致掌握輸入系統(tǒng)的輪廓。后面,我們將逐步分析子模塊 InputReader 和 InputDispatcher 的功能。

以上就是Android開發(fā)InputManagerService創(chuàng)建與啟動流程的詳細內(nèi)容,更多關于Android InputManagerService創(chuàng)建啟動的資料請關注腳本之家其它相關文章!

相關文章

最新評論