Android 輸入系統(一)InputManagerService

由於之前做藍芽hid的連線,以及輸入事件的讀取,突然想好好研究一下andorid輸入事件到底是怎麼管理的。

首先先看看系統服務InputManagerService的工作。以下都是基於Andorid4.3原始碼。

                                                                                                                                                                                                              
               

InputManagerService產生

一般的系統服務是在SystemServer.java的ServerThread中啟動,InputManagerService也不例外。

@Override
public void run() {
.....
Slog.i(TAG, "Input Manager");
//新建InputManagerService物件.
inputManager = new InputManagerService(context, wmHandler);
Slog.i(TAG, "Window Manager");
//這是視窗服務,先不說這個。
wm = WindowManagerService.main(context, power, display, inputManager,
uiHandler, wmHandler,
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot, onlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
//將InputManagerService新增到Serviceanager,便於其他使用者訪問
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
ActivityManagerService.self().setWindowManager(wm);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();//啟動服務
display.setWindowManager(wm);
//向DisplayManagerService設定InputManagerService
display.setInputManager(inputManager);
....
}

有上面程式碼總結其啟動過程:

  1. 建立InputManagerService物件  
    InputManagerService初始化時傳遞了一個引數wmHandler,其建立如下
    HandlerThread wmHandlerThread = new HandlerThread(“WindowManager”);
            wmHandlerThread.start();
    Handler wmHandler = new Handler(wmHandlerThread.getLooper());
    這說明InputManagerService和WindowManagerService會有功能上的一些互動。
  2. 呼叫InputManagerService的start函式。

                                                                                                                                                                                                              
               

InputManagerService 初始化工作

路徑:frameworks/base/services/java/com/android/server/input/InputManagerService.java

建立InputManagerService物件,會先呼叫其建構函式。建構函式如下

public InputManagerService(Context context, Handler handler) {
this.mContext = context;
this.mHandler = new InputManagerHandler(handler.getLooper());
//獲取config_useDevInputEventForAudioJack的值,該值為true,則通過inputEvent處理耳機插拔,否則通過UEent處理耳機插拔。預設為false。
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
mUseDevInputEventForAudioJack);
//呼叫native方法進行初始化操作
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
}

config_useDevInputEventForAudioJack設定是在frameworks/base/core/res/res/values/config.xml中

該值為TRUE使用Linux /dev/input/event子系統的變化來檢測開關的耳機/麥克風插孔,值為假時使用uevent框架。預設false。

<!-- When true use the linux /dev/input/event subsystem to detect the switch changes
on the headphone/microphone jack. When false use the older uevent framework. -->
<bool name="config_useDevInputEventForAudioJack">false</bool>

nativeInit呼叫到com_android_server_input_InputManagerService.cpp檔案中,

路徑:frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp

nativeInit程式碼如下

static jint 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物件
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
//返回 NativeInputManager物件的指標
return reinterpret_cast<jint>(im);
}

nativeInit中主要是建立一個NativeInputManager物件,用來連線java層和native層。

NativeInputManager程式碼也在com_android_server_input_InputManagerService.cpp該檔案中,接著看一下NativeInputManager的建構函式

NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
}
//建立EventHub物件,該物件主要用來訪問裝置節點,獲取輸入事件、裝置節點的新增和刪除
sp<EventHub> eventHub = new EventHub();
//建立InputManager物件,管理InputReader與InputDispatcher.
mInputManager = new InputManager(eventHub, this, this);
}

EventHub先不說了,之後再抽時間研究研究。

InputManager

路徑:frameworks/base/services/input/InputManager.cpp

其建構函式

InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
//建立InputDispatcher物件
mDispatcher = new InputDispatcher(dispatcherPolicy);
//建立InputReader物件
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
//初始化
initialize();
}

接著看initialize()函式

void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

建立一個InputReaderThread執行緒,供InputReader執行;

建立了一個InputDispatcherThread執行緒,供InputDispatcher執行。

InputDispatcher和InputReader建構函式中沒有什麼特別的東西,就不說了。

到這裡輸入系統的幾個重要部分都建立完成了。如下是其結構圖(網上找的)

                                                                                                                                                                                                              
               

InputManagerService啟動

在SystemServer中呼叫InputManagerService的start()方法正式啟動服務,函式如下:

public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);
//將inputmanagerservice新增到Wathcdog中,Watchdog檢測service是否正常工作
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
//監聽資料庫中的Settings.System.POINTER_SPEED、Settings.System.SHOW_TOUCHES的變化,具體還不太清楚。
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}

nativeStart()函式呼叫到com_android_server_input_InputManagerService.cpp中的nativeStart()函式

static void nativeStart(JNIEnv* env, jclass clazz, jint ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
//呼叫InputManager中的start方法。
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}

nativeStart主要是呼叫InputManager的start()方法,並將結果返回給java層。接著看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;
}

上述方法中工作就是將mDispatcherThread、mDispatcherThread執行緒開始執行。

待續。。。。。。。。。。