




版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 工程保安面試試題及答案
- 戀愛類型測試題及答案
- 2024年紡織供應(yīng)鏈協(xié)調(diào)機(jī)制研究試題及答案
- 2024年廣告設(shè)計(jì)師軟件應(yīng)用技巧試題及答案
- 紡織品檢測儀器使用技巧試題及答案
- 火災(zāi)預(yù)防測試題及答案
- 康復(fù)單選試題庫及答案
- 文言文成語試題及答案
- 合作營銷面試題及答案
- 紡織品檢驗(yàn)員證書考試解題技巧 試題及答案
- 2025至2030中國二亞砜(dmso)市場深度調(diào)研及投資建議研究報(bào)告
- 鏟車裝載機(jī)知識(shí)培訓(xùn)課件
- 2025年遼寧省葫蘆島市綏中縣中考一模語文試題含答案
- 2025屆山東省濰坊市高考二模歷史試題(含答案)
- 家政經(jīng)理培訓(xùn)課件
- 2024-2025學(xué)年高一下學(xué)期期中考試化學(xué)試卷
- 四川省南充市高級(jí)中學(xué)2024-2025學(xué)年高二下學(xué)期期中考試 化學(xué)(含答案)
- 輔警考試公安基礎(chǔ)知識(shí)考試試題庫及答案
- (正式版)SHT 3046-2024 石油化工立式圓筒形鋼制焊接儲(chǔ)罐設(shè)計(jì)規(guī)范
- 新華DCS軟件2.0版使用教程-文檔資料
- 新人教版五年級(jí)小學(xué)數(shù)學(xué)全冊奧數(shù)(含答案)
評(píng)論
0/150
提交評(píng)論