關(guān)聯(lián)系列
解析WMS系列
View體系系列
前言
很多同學(xué)可能會(huì)認(rèn)為輸入系統(tǒng)是不是和View的事件分發(fā)有些關(guān)聯(lián),確實(shí)是有些關(guān)聯(lián),只不過View事件分發(fā)只能算是輸入系統(tǒng)事件傳遞的一部分。這個(gè)系列講的輸入系統(tǒng)主要是我們不常接觸的,但還是需要去了解的那部分。
1. 輸入事件傳遞流程的組成部分
輸入系統(tǒng)是外界與Android設(shè)備交互的基礎(chǔ),僅憑輸入系統(tǒng)是無法完成輸入事件傳遞的,因此需要輸入系統(tǒng)和Android系統(tǒng)的其他成員來共同完成事件傳遞。輸入系統(tǒng)事件傳遞需要經(jīng)過以下幾個(gè)部分。

輸入事件傳遞流程可以大致的分為三個(gè)部分,分別是輸入系統(tǒng)部分、WMS處理部分和View處理部分。下面分別對(duì)這幾個(gè)部分進(jìn)行簡(jiǎn)單的介紹。
輸入系統(tǒng)部分
輸入系統(tǒng)部分主要又分為輸入子系統(tǒng)和InputManagerService組成(以下簡(jiǎn)稱IMS),在Android中還有一個(gè)IMS(IP Multimedia Subsystem)意為為IP多媒體子系統(tǒng),不要搞混了。
Android的輸入設(shè)備有很多種,比如屏幕、鍵盤、鼠標(biāo)、游戲手柄、操縱桿等等,其中應(yīng)用開發(fā)接觸最多的屏幕。當(dāng)輸入設(shè)備可用時(shí),Linux內(nèi)核會(huì)在/dev/input中創(chuàng)建對(duì)應(yīng)的設(shè)備節(jié)點(diǎn)。
用戶操作這些輸入設(shè)備時(shí)會(huì)產(chǎn)生各種事件比如按鍵事件、觸摸事件、鼠標(biāo)事件等。
輸入事件所產(chǎn)生的原始信息會(huì)被Linux內(nèi)核中的輸入子系統(tǒng)采集,原始信息由Kernel space的驅(qū)動(dòng)層一直傳遞到User space的設(shè)備節(jié)點(diǎn)。
Android提供了getevent和sendevent兩個(gè)工具幫助開發(fā)者從設(shè)備節(jié)點(diǎn)讀取輸入事件和寫入輸入事件。

IMS所做的工作就是監(jiān)聽/dev/input下的所有的設(shè)備節(jié)點(diǎn),當(dāng)設(shè)備節(jié)點(diǎn)有數(shù)據(jù)時(shí)會(huì)將數(shù)據(jù)進(jìn)行加工處理并找到合適的Window,將輸入事件派發(fā)給它。
WMS處理部分
在Android解析WindowManagerService(一)WMS的誕生這篇文章中我講過WMS的職責(zé)有四種,如下圖所示。

WMS的職責(zé)之一就是輸入系統(tǒng)的中轉(zhuǎn)站,WMS作為Window的管理者,會(huì)配合IMS將輸入事件交由合適的Window來處理。
View處理部分
View處理部分應(yīng)該是大家最熟悉的了,一般情況下,輸入事件最終會(huì)交由View來處理,應(yīng)用開發(fā)者就可以通過一些回調(diào)方法輕松得到這個(gè)事件的封裝類并對(duì)其進(jìn)行處理,比如onTouchEvent(MotionEvent ev)方法。關(guān)于View體系可以查看View體系這一系列文章。
2. IMS的誕生
輸入事件傳遞流程的組成部分我們已經(jīng)了解了,本系列主要講解輸入系統(tǒng)部分中IMS對(duì)輸入事件的處理,在這之前我們需要了解IMS的誕生。
2.1 SyetemServer處理部分
與AMS、WMS、PMS一樣,IMS的在SyetemServer進(jìn)程中被創(chuàng)建的,SyetemServer進(jìn)程用來創(chuàng)建系統(tǒng)服務(wù),不了解它的可以查看 Android系統(tǒng)啟動(dòng)流程(三)解析SyetemServer進(jìn)程啟動(dòng)過程 這篇文章。
從SyetemServer的入口方法main方法開始講起,如下所示。
frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) {
new SystemServer().run();
}
main方法中只調(diào)用了SystemServer的run方法,如下所示。
frameworks/base/services/java/com/android/server/SystemServer.java
private void run() {
...
try {
traceBeginAndSlog("StartServices");
//啟動(dòng)引導(dǎo)服務(wù)
startBootstrapServices();//1
//啟動(dòng)核心服務(wù)
startCoreServices();//2
//啟動(dòng)其他服務(wù)
startOtherServices();//3
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
...
}
在注釋1中的startBootstrapServices方法中用SystemServiceManager啟動(dòng)了ActivityManagerService、PowerManagerService、PackageManagerService等服務(wù)。在注釋2處的startCoreServices方法中則啟動(dòng)了DropBoxManagerService、BatteryService、UsageStatsService和WebViewUpdateService。注釋3處的startOtherServices方法中啟動(dòng)了CameraService、AlarmManagerService、VrManagerService等服務(wù)。這些服務(wù)的父類均為SystemService。從注釋1、2、3的方法可以看出,官方把系統(tǒng)服務(wù)分為了三種類型,分別是引導(dǎo)服務(wù)、核心服務(wù)和其他服務(wù),其中其他服務(wù)是一些非緊要和一些不需要立即啟動(dòng)的服務(wù)。這些系統(tǒng)服務(wù)總共有100多個(gè),我們熟知的AMS和PMS屬于引導(dǎo)服務(wù),WMS屬于其他服務(wù)。
本文要講的IMS屬于其他服務(wù),這里列出其他服務(wù)以及它們的作用,見下表。
| 其他服務(wù) | 作用 |
|---|---|
| CameraService | 攝像頭相關(guān)服務(wù) |
| AlarmManagerService | 全局定時(shí)器管理服務(wù) |
| InputManagerService | 管理輸入事件 |
| WindowManagerService | 窗口管理服務(wù) |
| VrManagerService | VR模式管理服務(wù) |
| BluetoothService | 藍(lán)牙管理服務(wù) |
| NotificationManagerService | 通知管理服務(wù) |
| DeviceStorageMonitorService | 存儲(chǔ)相關(guān)管理服務(wù) |
| LocationManagerService | 定位管理服務(wù) |
| AudioService | 音頻相關(guān)管理服務(wù) |
| ... | .... |
查看啟動(dòng)其他服務(wù)的注釋3處的startOtherServices方法。
frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
...
inputManager = new InputManagerService(context);//1
traceEnd();
traceBeginAndSlog("StartWindowManagerService");
// WMS needs sensor service ready
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
mSensorServiceStart = null;
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());//2
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
traceEnd();
...
}
注釋1處創(chuàng)建了IMS,注釋2處執(zhí)行了WMS的main方法,其內(nèi)部會(huì)創(chuàng)建WMS。需要注意的是,main方法的其中一個(gè)參數(shù)就是注釋1處創(chuàng)建的IMS,在本地第1節(jié)中我們知道WMS是輸入系統(tǒng)的中轉(zhuǎn)站,其內(nèi)部包含了IMS引用并不意外。緊接著將WMS和IMS添加到ServiceManager中進(jìn)行統(tǒng)一的管理。
2.2 InputManagerService構(gòu)造方法
我們接著來查看IMS的構(gòu)造方法。
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());//1
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());//2
...
}
注釋1處用android.display線程的Looper創(chuàng)建了InputManagerHandler,這樣InputManagerHandler會(huì)運(yùn)行在android.display線程,android.display線程是系統(tǒng)共享的單例前臺(tái)線程,這個(gè)線程內(nèi)部執(zhí)行了WMS的創(chuàng)建,具體見 Android解析WindowManagerService(一)WMS的誕生這篇文章。
注釋2處調(diào)用了nativeInit方法,很明顯是要通過JNI調(diào)用Navive方法。
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());//1
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
注釋1處創(chuàng)建了NativeInputManager,最后會(huì)調(diào)用reinterpret_cast運(yùn)算符將NativeInputManager指針強(qiáng)制轉(zhuǎn)換并返回(重新解釋比特位)。NativeInputManager的構(gòu)造函數(shù)如下所示。
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) {
...
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
NativeInputManager構(gòu)造函數(shù)中創(chuàng)建了EventHub和InputManager,EventHub通過Linux內(nèi)核的INotify與Epoll機(jī)制監(jiān)聽設(shè)備節(jié)點(diǎn),通過EventHub的getEvent函數(shù)讀取設(shè)備節(jié)點(diǎn)的增刪事件和原始輸入事件,本系列后續(xù)文章會(huì)詳細(xì)介紹EventHub。InputManager的構(gòu)造函數(shù)如下所示。
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();
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
InputManager構(gòu)造函數(shù)中創(chuàng)建了InputReader和InputDispatcher,InputReader會(huì)不斷循環(huán)讀取EventHub中的原始輸入事件,將這些原始輸入事件進(jìn)行加工后交由InputDispatcher,InputDispatcher中保存了WMS中的所有Window信息(WMS會(huì)將窗口的信息實(shí)時(shí)的更新到InputDispatcher中),這樣InputDispatcher就可以將輸入事件派發(fā)給合適的Window。InputReader和InputDispatcher都是耗時(shí)操作,因此在initialize函數(shù)中創(chuàng)建了供它們運(yùn)行的線程InputReaderThread和InputDispatcherThread。
InputManagerService構(gòu)造方法描繪了如下的IMS簡(jiǎn)圖。

從上面的簡(jiǎn)圖可以看出來,IMS主要的工作都在Native層中,這些內(nèi)容會(huì)在本系列的后續(xù)文章進(jìn)行介紹。
感謝
《深入理解Android》卷3
《深入理解Android內(nèi)核設(shè)計(jì)思想》
https://blog.csdn.net/u013604527/article/details/53432623
https://www.cnblogs.com/deng-tao/p/6094049.html