Android開發(fā)InputManagerService創(chuàng)建與啟動(dòng)流程_第1頁
Android開發(fā)InputManagerService創(chuàng)建與啟動(dòng)流程_第2頁
Android開發(fā)InputManagerService創(chuàng)建與啟動(dòng)流程_第3頁
Android開發(fā)InputManagerService創(chuàng)建與啟動(dòng)流程_第4頁
Android開發(fā)InputManagerService創(chuàng)建與啟動(dòng)流程_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第Android開發(fā)InputManagerService創(chuàng)建與啟動(dòng)流程目錄前言啟動(dòng)流程創(chuàng)建輸入系統(tǒng)啟動(dòng)輸入系統(tǒng)輸入系統(tǒng)就緒結(jié)束

前言

之前寫過幾篇關(guān)于輸入系統(tǒng)的文章,但是還沒有寫完,后來由于工作的變動(dòng),這個(gè)事情就一直耽擱了。而現(xiàn)在,在工作中,遇到輸入系統(tǒng)相關(guān)的事情也越來越多,其中有一個(gè)非常有意思的需求,因此是時(shí)候繼續(xù)分析InputManagerService。

InputManagerService系統(tǒng)文章,基于Android12進(jìn)行分析。

本文將以IMS簡稱InputManagerService。

啟動(dòng)流程

InputManagerService是一個(gè)系統(tǒng)服務(wù),啟動(dòng)流程如下

//SystemServer.java

privatevoidstartOtherServices(@NonNullTimingsTraceAndSlogt){

//..

//1.創(chuàng)建

inputManager=newInputManagerService(context);

//注冊服務(wù)

ServiceManager.addService(Context.INPUT_SERVICE,inputManager,

/*allowIsolated=*/false,DUMP_FLAG_PRIORITY_CRITICAL);

//保存wms的回調(diào)

inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());

//2.啟動(dòng)

inputManager.start();

try{

//3.就緒

if(inputManagerF!=null){

inputManagerF.systemRunning();

}catch(Throwablee){

reportWtf("NotifyingInputManagerServicerunning",e);

//...

IMS的啟動(dòng)流程分為三步

創(chuàng)建輸入系統(tǒng),建立上層與底層的映射關(guān)系。啟動(dòng)輸入系統(tǒng),其實(shí)就是啟動(dòng)底層輸入系統(tǒng)的幾個(gè)模塊。輸入系統(tǒng)就緒,上層會(huì)同步一些配置給底層輸入系統(tǒng)。

下面分三個(gè)模塊,分別講解這三步。

創(chuàng)建輸入系統(tǒng)

//InputManagerService.java

publicInputManagerService(Contextcontext){

this.mContext=context;

this.mHandler=newInputManagerHandler(DisplayThread.get().getLooper());

//配置為空

mStaticAssociations=loadStaticInputPortAssociations();

//默認(rèn)false

mUseDevInputEventForAudioJack=

context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);

//1.底層進(jìn)行初始化

//mPtr指向底層創(chuàng)建的NativeInputManager對象

mPtr=nativeInit(this,mContext,mHandler.getLooper().getQueue());

//空

StringdoubleTouchGestureEnablePath=context.getResources().getString(

R.string.config_doubleTouchGestureEnableFile);

//null

mDoubleTouchGestureEnableFile=TextUtils.isEmpty(doubleTouchGestureEnablePath)null:

newFile(doubleTouchGestureEnablePath);

LocalServices.addService(InputManagerInternal.class,newLocalService());

IMS構(gòu)造函數(shù),主要就是調(diào)用nativeInit()來初始化底層輸入系統(tǒng)。

//com_android_server_input_InputManagerService.cpp

staticjlongnativeInit(JNIEnv*env,jclass/*clazz*/,

jobjectserviceObj,jobjectcontextObj,jobjectmessageQueueObj){

//從Java層的MessageQueue中獲取底層映射的MessageQueue

spMessageQueuemessageQueue=android_os_MessageQueue_getMessageQueue(env,messageQueueObj);

if(messageQueue==nullptr){

jniThrowRuntimeException(env,"MessageQueueisnotinitialized.");

return0;

//創(chuàng)建NativeInputManager

NativeInputManager*im=newNativeInputManager(contextObj,serviceObj,

messageQueue-getLooper());

im-incStrong(0);

//返回指向NativeInputManager對象的指針

returnreinterpret_castjlong(im);

原來底層創(chuàng)建了NativeInputManager對象,然后返回給上層。

但是NativeInputManager并不是底層輸入系統(tǒng)的服務(wù),它只是一個(gè)連接上層輸入系統(tǒng)和底層輸入系統(tǒng)的橋梁而已。來看下它的創(chuàng)建過程

//com_android_server_input_InputManagerService.cpp

NativeInputManager::NativeInputManager(jobjectcontextObj,

jobjectserviceObj,constspLooperlooper):

mLooper(looper),mInteractive(true){

JNIEnv*env=jniEnv();

//1.保存上層的InputManagerService對象

mServiceObj=env-NewGlobalRef(serviceObj);

//2.初始化一些參數(shù)

AutoMutex_l(mLock);

//mLocked的類型是structLocked,這里初始化了一些參數(shù)

//這些參數(shù)會(huì)被上層改變

mLocked.systemUiVisibility=ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;

mLocked.pointerSpeed=0;

mLocked.pointerGesturesEnabled=true;

mLocked.showTouches=false;

mLocked.pointerCapture=false;

mLocked.pointerDisplayId=ADISPLAY_ID_DEFAULT;

mInteractive=true;

//3.創(chuàng)建并注冊服務(wù)InputManager

mInputManager=newInputManager(this,this);

defaultServiceManager()-addService(String16("inputflinger"),

mInputManager,false);

NativeInputManager構(gòu)造過程如下

創(chuàng)建一個(gè)全局引用,并通過mServiceObj指向上層的InputManagerService對象。初始化參數(shù)。這里要注意一個(gè)結(jié)構(gòu)體變量mLocked,它的一些參數(shù)都是由上層控制的。例如,mLocked.showTouches是由開發(fā)者選項(xiàng)中Showtaps決定的,它的功能是在屏幕上顯示一個(gè)觸摸點(diǎn)。創(chuàng)建并注冊服務(wù)InputManager。

原來,InputManager才是底層輸入系統(tǒng)的服務(wù),而NativeInputManagerService通過mServiceObj保存了上層InputManagerService引用,并且上層InputManagerService通過mPtr指向底層的NativeInputManager。因此,我們可以判定NativeInputManager就是一個(gè)連接上層與底層的橋梁。

我們注意到創(chuàng)建InputManager使用了兩個(gè)this參數(shù),這里介紹下NativeInputManager和InputManager的結(jié)構(gòu)圖

InputManager構(gòu)造函數(shù)需要的兩個(gè)接口正好是由NativeInputManager實(shí)現(xiàn)的,然而,具體使用這兩個(gè)接口的不是InputManager,而是它的子模塊。這些子模塊都是在InputManager的構(gòu)造函數(shù)中創(chuàng)建的

//InputManager.cpp

InputManager::InputManager(

constspInputReaderPolicyInterfacereaderPolicy,

constspInputDispatcherPolicyInterfacedispatcherPolicy){

//1.創(chuàng)建InputDispatcher對象,使用InputDispatcherPolicyInterface接口

mDispatcher=createInputDispatcher(dispatcherPolicy);

//2.創(chuàng)建InputClassifier對象,使用InputListenerInterface

mClassifier=newInputClassifier(mDispatcher);

//3.創(chuàng)建InputReader對象,使用InputReaderPolicyInterface和InputListenerInterface

mReader=createInputReader(readerPolicy,mClassifier);

//InputDispatcherFactory.cpp

spInputDispatcherInterfacecreateInputDispatcher(

constspInputDispatcherPolicyInterfacepolicy){

returnnewandroid::inputdispatcher::InputDispatcher(policy);

//InputReaderFactory.cpp

spInputReaderInterfacecreateInputReader(constspInputReaderPolicyInterfacepolicy,

constspInputListenerInterfacelistener){

returnnewInputReader(std::make_uniqueEventHub(),policy,listener);

InputManager構(gòu)造函數(shù)所使用的兩個(gè)接口,分別由InputDispatcher和InputReader所使用。因此InputManager向上通信的能力是由子模塊InputDispatcher和InputReader實(shí)現(xiàn)的。

InputManager創(chuàng)建了三個(gè)模塊,InputReader、InputClassifier、InputDispatcher。InputReader負(fù)責(zé)從EventHub中獲取事件,然后把事件加工后,發(fā)送給InputClassfier。InputClassifer會(huì)把事件發(fā)送給InputDispatcher,但是它會(huì)對觸摸事件進(jìn)行一個(gè)分類工作。最后InputDispatcher對進(jìn)行事件分發(fā)。

那么現(xiàn)在我們可以大致推算下輸入系統(tǒng)的關(guān)系圖,如下

這個(gè)關(guān)系圖很好的體現(xiàn)了設(shè)計(jì)模式的單一職責(zé)原則。

EventHub其實(shí)只屬于InputReader,因此要想解剖整個(gè)輸入系統(tǒng),我們得逐一解剖InputReader、InputClassifier、InputDispatcher。后面的一系列的文章將逐個(gè)來剖析。

啟動(dòng)輸入系統(tǒng)

//InputManagerService.java

publicvoidstart(){

Slog.i(TAG,"Startinginputmanager");

//1.啟動(dòng)native層

nativeStart(mPtr);

//AddourselftotheWatchdogmonitors.

Watchdog.getInstance().addMonitor(this);

//2.監(jiān)聽數(shù)據(jù)庫,當(dāng)值發(fā)生改變時(shí),通過native層

//監(jiān)聽Settings.System.POINTER_SPEED,這個(gè)表示手指的速度

registerPointerSpeedSettingObserver();

//監(jiān)聽Settings.System.SHOW_TOUCHES,這個(gè)表示是否在屏幕上顯示觸摸坐標(biāo)

registerShowTouchesSettingObserver();

//監(jiān)聽Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON

registerAccessibilityLargePointerSettingObserver();

//監(jiān)聽Settings.Secure.LONG_PRESS_TIMEOUT,這個(gè)多少毫秒觸發(fā)長按事件

registerLongPressTimeoutObserver();

//監(jiān)聽用戶切換

mContext.registerReceiver(newBroadcastReceiver(){

@Override

publicvoidonReceive(Contextcontext,Intentintent){

updatePointerSpeedFromSettings();

updateShowTouchesFromSettings();

updateAccessibilityLargePointerFromSettings();

updateDeepPressStatusFromSettings("userswitched");

},newIntentFilter(Intent.ACTION_USER_SWITCHED),null,mHandler);

//3.從數(shù)據(jù)庫獲取值,并傳遞給native層

updatePointerSpeedFromSettings();

updateShowTouchesFromSettings();

updateAccessibilityLargePointerFromSettings();

updateDeepPressStatusFromSettings("justbooted");

輸入系統(tǒng)的啟動(dòng)過程如下

啟動(dòng)底層輸入系統(tǒng)。其實(shí)就是啟動(dòng)剛剛說到的InputReader,InputDispatcher。監(jiān)聽一些廣播。因?yàn)檫@些廣播與輸入系統(tǒng)的配置有關(guān),當(dāng)接收到這些廣播,會(huì)更新配置到底層。直接讀取配置,更新到底層輸入系統(tǒng)。

第2步和第3步,本質(zhì)上其實(shí)都是更新配置到底層,但是需要我們對InputReader的運(yùn)行過程比較熟悉,因此這個(gè)配置更新過程,留到后面分析。

現(xiàn)在我們直接看下如何啟動(dòng)底層的輸入系統(tǒng)

//com_android_server_input_InputManagerService.cpp

staticvoidnativeStart(JNIEnv*env,jclass/*clazz*/,jlongptr){

NativeInputManager*im=reinterpret_castNativeInputManager*(ptr);

//調(diào)用InputManager::start()

status_tresult=im-getInputManager()-start();

if(result){

jniThrowRuntimeException(env,"Inputmanagercouldnotbestarted.");

通過JNI層的NativeInputManager這個(gè)橋梁來啟動(dòng)InputManager。

前面用一幅圖表明了NativeInputManager的橋梁作用,現(xiàn)在感受到了嗎?

status_tInputManager::start(){

//啟動(dòng)Dispatcher

status_tresult=mDispatcher-start();

if(result){

ALOGE("CouldnotstartInputDispatcherthreadduetoerror%d.",result);

returnresult;

//啟動(dòng)InputReader

result=mReader-start();

if(result){

ALOGE("CouldnotstartInputReaderduetoerror%d.",result);

mDispatcher-stop();

returnresult;

returnOK;

InputManager的啟動(dòng)過程很簡單,就是直接啟動(dòng)它的子模塊InputDispatcher和InputReader。

InputDispatcher和InputReader的啟動(dòng),都是通過InputThread創(chuàng)建一個(gè)線程來執(zhí)行任務(wù)。

//InputThread.cpp

InputThread::InputThread(std::stringname,std::functionvoid()loop,std::functionvoid()wake)

:mName(name),mThreadWake(wake){

mThread=newInputThreadImpl(loop);

mThread-run(mName.c_str(),ANDROID_PRIORITY_URGENT_DISPLAY);

注意InputThread可不是一個(gè)線程,InputThreadImpl才是一個(gè)線程,如下

//InputThread.cpp

classInputThreadImpl:publicThread{

public:

explicitInputThreadImpl(std::functionvoid()loop)

:Thread(/*canCallJava*/true),mThreadLoop(loop){}

~InputThreadImpl(){}

private:

std::functionvoid()mThreadLoop;

boolthreadLoop()override{

mThreadLoop();

returntrue;

當(dāng)線程啟動(dòng)后,會(huì)循環(huán)調(diào)用threadLoop(),直到這個(gè)函數(shù)返回false。從InputThreadImpl的定義可以看出,threadLoop()會(huì)一直保持循環(huán),并且每一次循環(huán),會(huì)調(diào)用一次mThreadLoop(),而函數(shù)mThreadLoop是由InputReader和InputDispacher在啟動(dòng)時(shí)傳入

//InputReader.cpp

status_tInputReader::start(){

if(mThread){

returnALREADY_EXISTS;

//線程啟動(dòng)后,循環(huán)調(diào)用loopOnce()

mThread=std::make_uniqueInputThread(

"InputReader",[this](){loopOnce();},[this](){mEventHub-wake();});

returnOK;

//InputDispatcher.cpp

status_tInputDispatcher::start(){

if(mThread){

returnALREADY_EXISTS;

//線程啟動(dòng)后,循環(huán)調(diào)用dispatchOnce()

mThread=std::make_uniqueInputThread(

"InputDispatcher",[this](){dispatchOnce();},[this](){mLooper-wake();});

returnOK;

現(xiàn)在,我們可以明白,InputReader啟動(dòng)時(shí),會(huì)創(chuàng)建一個(gè)線程,然后循環(huán)調(diào)用loopOnce()函數(shù),而InputDispatcher啟動(dòng)時(shí),也會(huì)創(chuàng)建一個(gè)線程,然后循環(huán)調(diào)用dispatchOnce()。

輸入系統(tǒng)就緒

//InputManagerService.java

publicvoidsystemRunning(){

mNotificationManager=(NotificationManager)mContext.getSystemService(

Context.NOTIFICATION_SERVICE);

synchronized(mLidSwitchLock){

mSystemReady=true;

//Sendtheinitiallidswitchstatetoanycallbackregisteredbeforethesystemwas

//ready.

intswitchState=getSwitchState(-1/*deviceId*/,InputDevice.SOURCE_ANY,SW_LID);

for(inti=0;imLidSwitchCallbacks.size();i++){

LidSwitchCallbackcallback=mLidSwitchCallbacks.get(i);

callback.notifyLidSwitchChanged(0/*whenNanos*/,switchState==KEY_STATE_UP);

//監(jiān)聽廣播,通知底層加載鍵盤布局

IntentFilterfilter=newIntentFilter(Intent.ACTION_PACKAGE_ADDED);

filter.addAction(Intent.ACTION_PACKAGE_REMOVED);

filter.addAction(Intent.ACTION_PACKAGE_CHANGED);

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論