本來想通過看老羅的書來學習這部分的源碼,但實際對比發現8.0的android已經和老羅那時候的很大不一樣,所以決定自己寫一下,也當做筆記.
從名字就可以知道,InputManagerService是跟輸入有關的,這不單單指鍵盤,只要是掛載在dev/input下面的設備都和它有關。
InputManagerService的啓動
InputManagerService是在SystemServe
r的startOtherServices
中被初始化和啓動的,此方法巨長,1200多行,我這裏只貼和InputManagerService相關的部分。
private void startOtherServices() {
...
InputManagerService inputManager = null;
...
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
traceEnd();
...
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
traceEnd();
...
traceBeginAndSlog("StartInputManager");
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
traceEnd();
...
}
可以看到,首先會調用InputManagerService的構造函數。構造函數的源碼如下:
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
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());
}
主要看如下這行
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
此行主要調用了nativeInit方法,來初始化,並返回一個指針地址,此方法的實現是在c++,如下
\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());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
這裏主要是new了一個NativeInputManager對象,此類的構造方法如下
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);
}
做了兩件事:
- 構造了一個EventHub對象,這個EventHub會去監聽
dev/input
這個目錄下文件的添加和刪除,也就是輸入設備的添加和刪除,還會監聽輸入設備的輸入事件 - 構造一個InputManager對象,並賦值給
mInputManager
全局變量,這個InputManager對象的構造會使用eventhub
作爲參數。
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();
}
1.初始化了兩個對象,mDispatcher
和mReader
,分別對應類InputDispatcher和InputReader,前者的作用是向當前激活的應用窗口分發輸入事件,後者則是監控輸入設備的事件。
2. 調用initialize()
方法
這個initialize()
方法的源碼如下:
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
新建了兩個分別爲InputReaderThread和InputDispatcherThread類型的線程,這裏先不研究線程的實現,先看下去。
到這裏NativeInputManager類的構造函數就跑完了,生成的實例地址賦值給了im
變量,並強制轉換成jlong
型的數據返回到java層的InputManagerService方法,並把返回值賦值給mPtr
變量。
再回到java層的SystemServer類的startOtherServices
方法:
private void startOtherServices() {
...
InputManagerService inputManager = null;
...
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
traceEnd();
...
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
traceEnd();
...
traceBeginAndSlog("StartInputManager");
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
traceEnd();
...
}
在新建一個InputManagerService對象並將對象賦值給inputManager
變量之後,會使用這個對象創建WindowManagerService,並將WindowManagerService的實力引用賦值給wm
變量,接着將wm
和inputManager
註冊到ServiceManager中。
接下來會調用inputManager.start()
方法,也就是啓動inputManager服務,我們看下具體源碼
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
....
}
主要就是調用了nativeStart(mPtr)
,並加入看門狗監控,不用多說,nativeStart
又是一個native方法。實現如下
\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.");
}
}
就是調用了native層InputManager的start
方法,這個方法的實現如下
\frameworks\base\services\core\jni\com_android_server_input_InputManagerService.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;
}
可以看到,做的事情也很簡單,就是啓動了之前新建的兩個線程。所以接下來就是看這兩個線程做了什麼。
到這裏InputManagerService就啓動完成了,可以發現主要代碼都是在native層,其實核心的部分就是啓動了兩個線程,再下一篇就學習兩個線程做了什麼事情。