最近接觸到了一個問題:耳機插入事件的由來,走讀了下IMS輸入系統服務的原始碼。同時,IMS輸入系統服務在Android的開發過程中,也經常出現,有必要了解下相關原理。
常見的輸入裝置有滑鼠、鍵盤、觸控式螢幕等,使用者通過輸入裝置與系統進行互動。
"uevent" 是 Linux 系統中的一種事件通知機制,用於向用戶空間傳送有關核心和裝置狀態變化的通知。這種機制通常用於裝置驅動程式、熱插拔事件以及裝置狀態變化等場景,以便使用者空間應用程式能夠在這些事件發生時做出相應的響應。
JNI,全稱Java Native Interface,是Java程式語言的一種程式設計框架,用於實現Java程式碼與其他程式語言(如C、C++)進行互動的介面。JNI允許Java程式呼叫原生程式碼(native code),即由其他程式語言編寫的程式碼,並且允許原生程式碼呼叫Java程式碼。通過JNI,Java程式可以存取底層系統功能、使用硬體裝置、呼叫第三方庫等。
監聽多個描述符的可讀/可寫狀態。等待返回時攜帶了可讀的描述符
Linux 核心所提供的一種檔案系統變化通知機制。可以監控檔案系統的變化,如檔案新建、刪除、讀寫等
通過螢幕的觸控事件,來分析IMS系統,相關如下
層級 | 模組 | 描述 | 原始碼 | 編譯產物 |
---|---|---|---|---|
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 |
InputManagerService是Android框架層一個非核心服務,主要是提供一個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();
...
}
此處做一些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());
...
}
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);
...
}
該方法為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);
}
...
}
該模組為JNI模組,主要處理Java方法與c++方法對映關係,即IMS服務與InputFlinger模組的通訊橋樑。
(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);
}
獲取上一個階段建立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.");
}
}
input事件的管理類,資料傳遞類,也是輸入系統native層核心的模組。
ps: 根據字典裡的定義,flinger是指出軌的人。在SurfaceFlinger的例子中,它把可視資料扔給surface AudioFlinger把音訊資料扔給適當的接收者。它們只是「可愛」的詞…