???????針對平時工作中出現(xiàn)的問題,學(xué)習(xí)了一下Input處理機(jī)制,對在觸摸屏幕或按鍵后事件傳到應(yīng)用進(jìn)行處理整個過程有了一個大概的了解,將這段時間的所學(xué)所得在此記錄一下。
???????IMS原理涉及的知識點(diǎn)比較多,為了方便閱讀,總共分為六篇文章:
???????Android IMS原理解析之InputReader
???????Android IMS原理解析之InputDispatcher
???????Android IMS原理解析之InputChannel
???????Android IMS原理解析之processEvent
???????Android IMS原理解析之dispatchEvent
Android輸入系統(tǒng)
簡介
???????輸入事件的源頭是位于dev/input/下的設(shè)備節(jié)點(diǎn),即:當(dāng)我們觸摸屏幕或按鍵后會在該節(jié)點(diǎn)下生成數(shù)據(jù),而輸入系統(tǒng)的終點(diǎn)是由WMS管理的某個窗口。
???????最初的輸入事件為內(nèi)核生成的原始事件,而最終交付給窗口的則是KeyEvent或MotionEvent對象。
???????Android輸入系統(tǒng)的主要工作是讀取設(shè)備節(jié)點(diǎn)中的原始事件,將其加工封裝,然后派發(fā)給一個指定的窗口以及窗口中的控件。這個過程由InputManagerService系統(tǒng)服務(wù)為核心的多個參與者共同完成。
核心成員
1.Linux內(nèi)核
???????接受輸入設(shè)備的中斷,并將原始事件的輸入寫入設(shè)備節(jié)點(diǎn)中;
2.設(shè)備節(jié)點(diǎn)
???????作為內(nèi)核和IMS的橋梁,將原始事件的數(shù)據(jù)暴露給用戶空間,以便IMS可以從中讀取事件;
3.InputManagerService
???????Android系統(tǒng)服務(wù),它分為java層和native層兩部分;java層負(fù)責(zé)與WMS通信,native層則是InputReader和InputDispatcher兩個輸入系統(tǒng)關(guān)鍵組件的運(yùn)行容器;
4.EventHub
???????直接訪問所有的設(shè)備節(jié)點(diǎn)。它通過一個名為getEvent()的函數(shù)將所有輸入系統(tǒng)相關(guān)的待處理的底層事件返回給使用者。這些事件包括原始輸入事件、設(shè)備節(jié)點(diǎn)的增刪等;
5.InputReader
???????IMS中的關(guān)鍵組件之一,它運(yùn)行于一個獨(dú)立的線程中,負(fù)責(zé)管理輸入設(shè)備的列表與配置,以及進(jìn)行輸入事件的加工處理。它通過其線程循環(huán)不斷地通過getEvents()函數(shù)從EventHub中將事件取出并進(jìn)行處理。對于設(shè)備節(jié)點(diǎn)的增刪事件,它會更新輸入設(shè)備列表與配置。對于原始輸入事件,InputReader對其進(jìn)行翻譯、組裝、封裝為包含更多信息、更具可讀性的輸入事件,然后交給InputDispatcher進(jìn)行派發(fā);
6.InputReaderPolicy
???????它為InputReader的事件加工處理提供一些策略配置,例如鍵盤布局信息等;
7.InputDispatcher
???????IMS中的另一個關(guān)鍵組件,它也運(yùn)行于一個獨(dú)立的線程中。InputDispatcher中保管了來自WMS的所有窗口的信息,其收到來自InputReader的輸入事件后,會在其保管的窗口中尋找合適的窗口,并將事件派發(fā)給此窗口;
8.InputDispatcherPolicy
???????它為InputDispatcher的派發(fā)過程提供策略控制。例如截取某些特定的輸入事件用作特殊用途,或者阻止將某些事件派發(fā)給目標(biāo)窗口。一個典型的例子就是HOME鍵被InputDispatcherPolicy截取到PhoneWindowManager中進(jìn)行處理,并阻止窗口收到HOME鍵按下的事件;
9.WMS
???????不是輸入系統(tǒng)的一員,但它對InputDispatcher的正常工作起到重要作用。當(dāng)新建窗口時,WMS為新窗口和IMS創(chuàng)建了事件傳遞所用的通道。另外,WMS還將所有窗口的信息,包括窗口的可點(diǎn)擊區(qū)域,焦點(diǎn)窗口等信息,實(shí)時的更新到IMS的InputDispatcher中,使得InputDispatcher可以正確地將事件派發(fā)到指定的窗口;
10.ViewRootImpl
???????對某些窗口,如壁紙窗口、SurfaceView的窗口來說,窗口就是輸入事件派發(fā)的終點(diǎn)。而對其他的activity、對話框等使用了Android控件系統(tǒng)的窗口來說,輸入事件的終點(diǎn)是控件View。ViewRootImpl將窗口所接收的輸入事件沿著控件樹將事件派發(fā)給感興趣的控件;
總結(jié)
???????內(nèi)核將原始事件寫入設(shè)備節(jié)點(diǎn)中,InputReader不斷地通過EventHub將原始事件取出來并翻譯加工成Android輸入事件,然后交給InputDispatcher。InputDispatcher根據(jù)WMS提供的窗口信息將事件交給合適的窗口。窗口的ViewRootImpl對象再沿著控件樹將事件派發(fā)給感興趣的控件。控件對其收到的事件做出響應(yīng),更新自己的畫面、執(zhí)行特定的動作。所有這些參與者以IMS為核心,構(gòu)建Android輸入體系。
IMS啟動及構(gòu)成
???????IMS分為java和native兩部分,其啟動過程是從java部分的初始化開始,進(jìn)而完成native部分的初始化;
???????同其他核心服務(wù)一樣,IMS運(yùn)行在system_server進(jìn)程里面,在startOtherServices()里面啟動:
private void startOtherServices() {
.......
.......
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
traceEnd();
traceBeginAndSlog("StartInputManager");
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
traceEnd();
.......
......
}
???????通過啟動邏輯可以看到,在創(chuàng)建完IMS實(shí)例后,先執(zhí)行了setWindowManagerCallbacks然后執(zhí)行了start(),接下來進(jìn)入InputManagerService源碼中一起看一下內(nèi)部實(shí)現(xiàn)邏輯:
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
private static native void nativeStart(long ptr);
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
......
}
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);
.......
}
//該方法設(shè)置了callbacks,后續(xù)native層的callback最終會調(diào)用到這里
public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
mWindowManagerCallbacks = callbacks;
}
???????在構(gòu)造方法內(nèi),執(zhí)行了nativeInit(),在start()中執(zhí)行了nativeStart(),以上兩個方法都是native方法,具體的邏輯是在native層實(shí)現(xiàn)的,對應(yīng)的類路徑為:base/services/core/jni/com_android_server_input_InputManagerService.cpp,接下來先一起看一下nativeInit():
nativeInit()
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());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
???????在nativeInit方法內(nèi)部,創(chuàng)建了NativeInputManager對象:
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface {
......
......
}
NativeInputManager::NativeInputManager(jobject contextObj,jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(serviceObj);
.......
.......
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
???????可以看到,NativeInputManager繼承了InputReaderPolicyInterface、InputDispatcherPolicyInterface等,后續(xù)會講到,然后回到構(gòu)造方法,在構(gòu)造方法內(nèi)部,先創(chuàng)建了EventHub,然后創(chuàng)建InputManager,并將自身和EventHub實(shí)例作為參數(shù)傳入,再看一下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();
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
???????在實(shí)例化InputManager時,會創(chuàng)建InputDispatcher,然后創(chuàng)建InputReader,并把eventHub和mDispatcher作為參數(shù)傳入,參數(shù)dispatcherPolicy和readerPolicy的實(shí)現(xiàn)都是NativeInputManager及參數(shù)mDispatcher,在后續(xù)事件傳遞過程中會用到,接下來會講;然后執(zhí)行了initialize(),分別創(chuàng)建了InputReader運(yùn)行的線程InputReaderThread和InputDispatcher運(yùn)行的線程InputDispatcherThread;
???????總結(jié)一下:在執(zhí)行nativeInit()后,會創(chuàng)建NativeInputManager對象,然后在NativeInputManager內(nèi)部創(chuàng)建了EventHub和InputManager對象,接著在InputManager內(nèi)部創(chuàng)建了InputReader和InputDispatcher對象,并創(chuàng)建了InputReaderThread和InputDispatcherThread,用一張圖概況一下:
???????Java層IMS的主要工作是為InputReaderPolicy和InputDispatcherPolicy提供實(shí)現(xiàn),以及與Android系統(tǒng)服務(wù)進(jìn)行協(xié)作,最主要的就是WMS;
???????NativeInputManager位于IMS的jni層,負(fù)責(zé)native層的組件與java層的IMS的相互通信,同時它為主要工作是為InputReader和InputDispatcher提供策略請求接口InputReaderPolicyInterface和InputDispatcherPolicyInterface,策略請求被它轉(zhuǎn)發(fā)為Java層的IMS,由IMS最終確定;
???????InputManager由NativeInputManager創(chuàng)建,是InputReader和InputDispatcher的運(yùn)行容器,并創(chuàng)建了InputReaderThread和InputDispatcherThread分別承載InputReader和InputDispatcher的運(yùn)行;
nativeStart()
???????接著上面分析,在執(zhí)行nativeInit()后,會執(zhí)行nativeStart():
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.");
}
}
???????可以看到,實(shí)際上是調(diào)用InputManager的start()方法:
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputReader thread due to error %d.", result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
???????在start()內(nèi)部,啟動了InputReader運(yùn)行的線程InputReaderThread和InputDispatcher運(yùn)行的線程InputDispatcherThread;
???????system_server在啟動IMS時,執(zhí)行的流程如圖所示:
Thread運(yùn)行
???????當(dāng)兩個線程啟動后,InputReader在其線程循環(huán)中不斷地從EventHub中抽取原始輸入事件,進(jìn)行加工處理后將加工所得的事件放入InputDispatcher的派發(fā)隊(duì)列中;InputDispatcher則在其線程循環(huán)中將派發(fā)隊(duì)列中的事件取出,查找合適的窗口,將事件寫入窗口的事件接收管道中;窗口事件接收線程的Looper從管道中將事件取出,交由事件處理函數(shù)進(jìn)行事件響應(yīng)。
成員關(guān)系
???????從上面的分析可以看到,在創(chuàng)建IMS時,涉及到許多類,先將關(guān)系整理如下,接下來通過功能詳細(xì)分析:
???????接下來從事件讀取開始分析,對應(yīng)文章為:Android IMS原理解析之InputReader