本系列博客主要描述Android 7.1系統中輸入管理服務InputManagerService的源碼分析。
概述
本文主要描述了InputManagerService服務的初始化和啟動,在Android7系統上InputManagerService服務的框架如下所示:
注:箭頭的方向,并不能真實代表數據流向方向。
1、FrameWorks層:inputManagerService對外提供服務的模塊;
2、JNI層:因為InputManagerService要去管理底層硬件輸入設備,而在Android 7系統的所有與硬件相關的部分,都會涉及到JNI層。用C++代碼去管理硬件設備;
3、Inputfliger: 是InputManager事件處理的核心事件,包括事件的獲取和分發等;
4、kernel層,主要涉及的input輸入驅動,并且將設備產生的事件通過inpu子系統上傳給C++ inputflinger層;
5、硬件層,具體的輸入設備,因為輸入設備的類型很過,這里只是大概羅列出了嵌入式設備上常用的幾個;
InputManagerService服務的初始化和啟動比較簡單,由SystemServer服務創建并拉起。
源碼路徑
本文描述中涉及的源碼有:
frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
framesworks/native/services/inputflinger/inputManager.cpp
InputManagerServie服務的初始化
java層的服務初始化
在系統核心服務SystemServer初始化中,在啟動其他服務startOtherService方法中,會創建InputManagerService服務。代碼片段如下所示:
frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {......traceBeginAndSlog("StartInputManagerService");/* 創建InputManagerService服務 */inputManager = new InputManagerService(context);Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);traceBeginAndSlog("StartWindowManagerService");wm = WindowManagerService.main(context, inputManager,mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,!mFirstBoot, mOnlyCore);ServiceManager.addService(Context.WINDOW_SERVICE, wm);/* 注冊InputManagerServie服務 */ServiceManager.addService(Context.INPUT_SERVICE, inputManager);Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);if (!disableVrManager) {traceBeginAndSlog("StartVrManagerService");mSystemServiceManager.startService(VrManagerService.class);Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}mActivityManagerService.setWindowManager(wm);/* 設置InputManagerService的窗口回調接口 */inputManager.setWindowManagerCallbacks(wm.getInputMonitor());......}
1、在systemServer的服務中創建InputManagerService;
2、設置InputManagerService的窗口回調接口,因此最終的事件要傳遞給上層App的Windows窗口去處理;
創建InputManagerService并進入它的構造方法繼續初始化,代碼片段如下所示:
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public InputManagerService(Context context) {this.mContext = context;/* 創建Handler, 并使用displayThead現成的Looper */this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());mUseDevInputEventForAudioJack =context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="+ mUseDevInputEventForAudioJack);/* 調用InputManagerService服務的JNI方法nativeInit繼續初始化 */mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());String doubleTouchGestureEnablePath = context.getResources().getString(R.string.config_doubleTouchGestureEnableFile);mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :new File(doubleTouchGestureEnablePath);LocalServices.addService(InputManagerInternal.class, new LocalService());}
在構造方法中:
1、創建InputManagerHander,并使用DisplayThread線程的Looper處理Handler消息;
2、調用InputManagerService服務的JNI方法nativeInit()方法繼續初始化,并且將mHandler.getLooper().getQueue()隊列傳遞給JNI層,在前面的初始化中InputManagerService自己的Handler使用了DisplayThread的Looper, 也就是說,在這個地方等同于將DisplayThread線程的消息隊列傳遞給了InputManagerService的JNI層;
native層的初始化
根據前面的描述,InputManagerService服務的Java層調用nativeInit方法,繼續初始化Native層,初始化代碼片段,如下所示:
a、nativeInit()
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,jobject serviceObj, jobject contextObj, jobject messageQueueObj) {/* 將java層的messageQueue對象轉化到對應的native層的messageQueue對象 */sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);if (messageQueue == NULL) {jniThrowRuntimeException(env, "MessageQueue is not initialized.");return 0;}/* 創建NativeInputManager輸入管理 */NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,messageQueue->getLooper());im->incStrong(0);/* 將native層的對象指針返回java層 */return reinterpret_cast<jlong>(im);
}
1、將java層的MessageQueue對象轉化到它對應native層的C++對象,這個比較管理,涉及到后面的事件處理,暫時先不描述;
2、創建NativeInputManager對象;
3、返回JNI創建的C++對象的指針返回java層;
b、NativeInputManger的初始化
NativeInputManager的初始化,關鍵代碼片段如下所示:
NativeInputManager::NativeInputManager(jobject contextObj,jobject serviceObj, const sp<Looper>& looper) :mLooper(looper), mInteractive(true) {....../* 創建EventHub() 事件獲取*/sp<EventHub> eventHub = new EventHub();mInputManager = new InputManager(eventHub, this, this);
1、創建EventHub()對象,該對象,主要就是獲取輸入事件(各種輸入設備產生的事件和軟件模擬產生的事件);
2、創建InputManager對象;
c、InputManager對象的初始化
framesworks/native/services/inputflinger/inputManager.cpp
InputManager對象初始化中如下所示:
const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {/* 創建事件分發對象 */mDispatcher = new InputDispatcher(dispatcherPolicy);/* 創建事件獲取對象 */mReader = new InputReader(eventHub, readerPolicy, mDispatcher);initialize();
1、創建事件分發對象;
2、創建事件獲取對象;
3、創建事件分發和事件獲取線程,如下所示:
void InputManager::initialize() {/* 創建事件獲取線程 */mReaderThread = new InputReaderThread(mReader);/* 創建事件分發線程 */mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
至此,InputManagerService服務從java層的初始化過程到JNI層的初始化過程,描述完成.
InputManagerService服務啟動
Java層的啟動
InputManagerSerivice服務在Java層的啟動,也是在SystemServer服務中完成。非常簡單。執行代碼片段如下所示:
frameworks/base/services/java/com/android/server/SystemServer.java
/* 設置InputManagerService的窗口回調接口 */inputManager.setWindowManagerCallbacks(wm.getInputMonitor());/* 啟動InputManagerService服務 */inputManager.start();
然后調用InputManagerService中的start方法,關鍵執行代碼片段如下:
public void start() {Slog.i(TAG, "Starting input manager");/* 調用JNI層nativeStart */nativeStart(mPtr);// Add ourself to the Watchdog monitors.Watchdog.getInstance().addMonitor(this);
1、直接調用jni層的nativeStart的接口;
Native層的啟動
jni層的啟動,關鍵代碼片段如下所示:
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.");}
}
最終調用InputManager的start方法
framesworks/native/services/inputflinger/inputManager.cpp
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;
}
總結
1、InputManagerService服務的注冊和啟動都在SystemServer服務中完成;
2、InputManagerservice服務初始化過程中會在native層注冊事件獲取和分發的線程;
3、整個初始化過程中,從Java層到native層都傳遞了DisplayThread線程的Looper的MessageQueue;