Android 輸入系統介紹

2023-11-24 18:00:15

一、目的

        最近接觸到了一個問題:耳機插入事件的由來,走讀了下IMS輸入系統服務的原始碼。同時,IMS輸入系統服務在Android的開發過程中,也經常出現,有必要了解下相關原理。

  1. 學習下IMS輸入系統的原始碼設計,瞭解該模組承擔的業務職責,熟悉Android結構
  2. 瞭解Android螢幕點選事件、物理按鍵事件的分發規則

二、環境

  1. 版本:Android 11
  2. 平臺:高通 QCM2290

三、相關概念

3.1 輸入裝置

        常見的輸入裝置有滑鼠、鍵盤、觸控式螢幕等,使用者通過輸入裝置與系統進行互動。

3.2 UEVENT機制

        "uevent" 是 Linux 系統中的一種事件通知機制,用於向用戶空間傳送有關核心和裝置狀態變化的通知。這種機制通常用於裝置驅動程式、熱插拔事件以及裝置狀態變化等場景,以便使用者空間應用程式能夠在這些事件發生時做出相應的響應。

3.3 JNI

        JNI,全稱Java Native Interface,是Java程式語言的一種程式設計框架,用於實現Java程式碼與其他程式語言(如C、C++)進行互動的介面。JNI允許Java程式呼叫原生程式碼(native code),即由其他程式語言編寫的程式碼,並且允許原生程式碼呼叫Java程式碼。通過JNI,Java程式可以存取底層系統功能、使用硬體裝置、呼叫第三方庫等。

3.4 EPOLL機制

        監聽多個描述符的可讀/可寫狀態。等待返回時攜帶了可讀的描述符

3.5 INotify

        Linux 核心所提供的一種檔案系統變化通知機制。可以監控檔案系統的變化,如檔案新建、刪除、讀寫等

四、詳細設計

通過螢幕的觸控事件,來分析IMS系統,相關如下

4.1 結構圖

4.2 程式碼結構

層級 模組 描述 原始碼 編譯產物
Framework InputManagerService xxx frameworks/base/services/core/java/ out/target/product/qssi/system/framework/services.jar
Native NativeInputManager xxx frameworks/base/services/core/jni/ out/target/product/qssi/system/lib64/libandroid_servers.so
Native Inputflinger xxx frameworks/native/services/inputflinger/ out/target/product/qssi/system/lib64/libinputflinger.so
Native Inputreader xxx frameworks/native/services/inputflinger/reader out/target/product/qssi/system/lib64/libinputreader.so
Native Inputdispatcher xxx frameworks/native/services/inputflinger/dispatcher/ (靜態庫)out/soong/.intermediates/frameworks/native/services/inputflinger/dispatcher/libinputdispatcher/android_arm64_armv8-a_static/libinputdispatcher.a
Native NativeInputEventReceiver xxx frameworks/base/core/jni/ out/target/product/qssi/system/lib64/libandroid_runtime
Native InputChannel xxx frameworks/native/libs/input/ out/target/product/qssi/system/lib64/libinput.so

4.3 InputManagerService模組

        InputManagerService是Android框架層一個非核心服務,主要是提供一個IMS輸入系統啟動的入口,同時對應用層提供業務相關介面。

4.3.1 IMS服務入口

        Android裝置開機後,會啟動system_server程序,InputManagerService服務(以下簡稱IMS)在該程序被喚起。

@frameworks\base\services\java\com\android\server\SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ...
    t.traceBegin("StartInputManagerService");
    inputManager = new InputManagerService(context);//新建IMS範例
    t.traceEnd();
    ...
    t.traceBegin("StartInputManager");
    inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());//設定表單事件監聽
    inputManager.start();//啟動IMS服務
    t.traceEnd();
    ...
}

4.3.2 IMS初始化

        此處做一些IMS相關的初始化操作,會呼叫nativeInit方法,獲取一個NativeInputManager物件,類似於一個控制程式碼。

@frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
private static native long nativeInit(InputManagerService service,
        Context context, MessageQueue messageQueue);
public InputManagerService(Context context) {
    ...
    mStaticAssociations = loadStaticInputPortAssociations();
    mUseDevInputEventForAudioJack =
            context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
    Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
            + mUseDevInputEventForAudioJack);
    mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    ...
}

4.3.3 IMS啟動

        InputManagerService通過start方法啟動,會呼叫nativeStart方法,該方法為Native方法

@frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
private static native void nativeStart(long ptr);
public void start() {
    Slog.i(TAG, "Starting input manager");
    nativeStart(mPtr);

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

4.3.4 IMS訊息監聽

        該方法為Native的回撥方法,用於上報IMS事件,如耳機插入事件等。

@frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
// Native callback.
private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
    ...
    if ((switchMask & SW_LID_BIT) != 0) {
        final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
        mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
    }

    if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
        final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
        mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
    }

    if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
        mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
                    switchMask);
    }
    ...
}

4.4 NativeInputManager模組

        該模組為JNI模組,主要處理Java方法與c++方法對映關係,即IMS服務與InputFlinger模組的通訊橋樑。

4.4.1 nativeInit初始化

(1)新建一個NativeInputManager物件,並將該物件返回給java層

@\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);
    ...
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

(2)建立InputManager管理類,主要用於管理Input事件分發、事件讀取行為

@\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) {
    JNIEnv* env = jniEnv();
    ...
    mInputManager = new InputManager(this, this);
    defaultServiceManager()->addService(String16("inputflinger"),
            mInputManager, false);
}

4.4.2 nativeStart啟動

獲取上一個階段建立NativeInputManager物件,並參照start啟動該模組

@\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.");
    }
}

4.5 Inputflinger模組

input事件的管理類,資料傳遞類,也是輸入系統native層核心的模組。
ps: 根據字典裡的定義,flinger是指出軌的人。在SurfaceFlinger的例子中,它把可視資料扔給surface AudioFlinger把音訊資料扔給適當的接收者。它們只是「可愛」的詞…