Openharmony撥打電話全流程介紹
??想了解更多關(guān)于開源的內(nèi)容,請(qǐng)?jiān)L問(wèn):??
1、背景介紹
3.1版本標(biāo)準(zhǔn)系統(tǒng)增加了通話相關(guān)的聯(lián)系人應(yīng)用,來(lái)電應(yīng)用等,在系統(tǒng)服務(wù)層面電話相關(guān)功能也比較完善,相關(guān)modem模塊目前從代碼中看到有美格智能的slm790和紫光展銳的模塊,之前介紹過(guò)??鴻蒙電話服務(wù)子系統(tǒng)功能劃分介紹??,只是對(duì)官方文檔的介紹,可以通過(guò)這個(gè)文檔先去了解一下各個(gè)功能模塊。今天從上到下分析下代碼調(diào)用流程,以撥打電話為例介紹鴻蒙電話子系統(tǒng)的各個(gè)部分。電話服務(wù)子系統(tǒng)的在/base/telephony目錄下,大概有700多個(gè)文件,11萬(wàn)多行代碼。
2、應(yīng)用層js代碼介紹
應(yīng)用層撥打電話的應(yīng)用是聯(lián)系人,聯(lián)系人應(yīng)用的通話記錄,聯(lián)系人查看,撥號(hào)盤和收藏都有對(duì)撥電話的調(diào)用。
最終調(diào)用的是app.js中的call函數(shù),此函數(shù)調(diào)用的是@ohos.telephony.call中的dial方法。
應(yīng)用層只是調(diào)用電話框架層的api,這個(gè)api就是@ohos.telephony.call提供的。
3、撥打電話NAPI實(shí)現(xiàn)介紹
應(yīng)用層調(diào)用的是js函數(shù),而電話服務(wù)層是c語(yǔ)言實(shí)現(xiàn)的,二者之間的橋梁就是通過(guò)NAPI實(shí)現(xiàn)的,有關(guān)NAPI介紹請(qǐng)參照這幾篇文章源碼解析之JavaScript API框架(NAPI)。簡(jiǎn)單來(lái)說(shuō)js的函數(shù)在c層都有對(duì)應(yīng)的實(shí)現(xiàn),它們之間是一一對(duì)應(yīng)的關(guān)系,比如js的dial對(duì)應(yīng)的是c++的DialCall,相關(guān)代碼如下,這部分代碼在通話管理模塊。
NapiCallManager::DialCall函數(shù)中調(diào)用的函數(shù)是。
HandleAsyncWork(env, asyncContext, “DialCall”, NativeDialCall, NativeDialCallBack)。
之后跳轉(zhuǎn)到了CallManagerClient中的DialCall,然后是CallManagerProxy::DialCall,如下:
4、如何從CallManagerServiceProxy到CallManagerServiceStub
到CallManagerProxy::DialCall中后代碼突然不清晰了,callManagerServicePtr_是什么,它的DialCall在哪里,順藤摸瓜,它的位置如下:
SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager()和managerPtr->GetSystemAbility(systemAbilityId_)是理解下一步調(diào)用位置的關(guān)鍵。
這里涉及到了另外一個(gè)知識(shí)點(diǎn),就是進(jìn)程通信,這里使用了ipc機(jī)制,可以查看官方文檔的介紹。
在目錄foundation/comminucotion下的ipc下有readme文檔,貼一張?jiān)瓐D:
大體意思是proxy通過(guò)samgr也就是SystemAbilityManager,去調(diào)用跨進(jìn)程的Stub中的函數(shù),代碼層面可以通過(guò)systemAbilityId_和接口類去定位函數(shù)調(diào)用的對(duì)應(yīng)關(guān)系,這里的abilityid是TELEPHONY_CALL_MANAGER_SYS_ABILITY_ID,接口類是ICallManagerService,通過(guò)查找定位到了CallManagerServiceProxy和CallManagerServiceStub。
函數(shù)調(diào)用就是從CallManagerServiceProxy::DialCall過(guò)渡到了CallManagerServiceStub::OnDialCall。
5、從CallControlManager::DialCall到 蜂窩通話(cellular_call)模塊
CallManagerServiceStub::OnDialCall中調(diào)用到了CallControlManager::DialCall,然后又走到了。
CallRequestHandlerService::DialCall(),這里調(diào)用了一個(gè)發(fā)送事件函數(shù),這是一種線程異步處理機(jī)智可以看這篇文章,只要有發(fā)就有收,我們找到收事件的地方。
對(duì)應(yīng)關(guān)系在如下位置,由此找到了函數(shù)CallRequestHandler::DialCallEvent。
CallRequestHandler::DialCallEvent中有針對(duì)類型的判斷:
我們走CallRequestProcess::DialRequest分支,然后走到了CellularCallIpcInterfaceProxy::Dial。
在這里我們又遇到了ipc,同樣的方法此時(shí)id是TELEPHONY_CELLULAR_CALL_SYS_ABILITY_ID。
找到stub函數(shù)位置是CellularCallStub::Dial,此時(shí)已經(jīng)到了蜂窩通話模塊目錄。
6、從蜂窩通話(cellular_call)到 核心服務(wù)(core_service)
CellularCallStub::Dial直接調(diào)用的是CSControl::Dial。
在這里又出現(xiàn)了類型判斷,判斷手機(jī)網(wǎng)絡(luò)制式是gsm還是cdma,了解通信行業(yè)的都知道gsm和cdma是2G時(shí)代的兩種制式標(biāo)準(zhǔn),一個(gè)是歐洲主導(dǎo)的,一個(gè)是高通主導(dǎo)的,扯得有點(diǎn)遠(yuǎn),繼續(xù)看代碼。
二者最終調(diào)用的是CSControl::EncapsulateDialCommon,然后CellularCallConnectionCS::DialRequest。
然后進(jìn)入到了核心服務(wù)模塊。
然后是TelRilManager::Dial和TelRilCall::Dial。
7、從核心服務(wù)(core_service)到 RIL適配層(RIL Adapter)
TelRilCall::Dial中調(diào)用了TelRilBase基類的SendBufferEvent(HREQ_CALL_DIAL, wData)函數(shù)代碼如下:
cellularRadio_這個(gè)成員的初始化實(shí)在TelRilManager中。
這又涉及到了另外一個(gè)知識(shí)點(diǎn)驅(qū)動(dòng)相關(guān)看這篇OpenHarmony HDF HDI基礎(chǔ)能力分析與使用,對(duì)modem的操作在RIL適配層被當(dāng)做了驅(qū)動(dòng)服務(wù)來(lái)使用的,SendRequest就是對(duì)驅(qū)動(dòng)的異步調(diào)用,在驅(qū)動(dòng)中的函數(shù)RilAdapterDispatch負(fù)責(zé)對(duì)SendRequest的接收處理。
而這個(gè)處理函數(shù)是驅(qū)動(dòng)加載時(shí)運(yùn)行起來(lái)的。
RilAdapterDispatch中的函數(shù)DispatchRequest位于HRilManager中,然后調(diào)用DispatchModule。
繼續(xù)調(diào)用HRilManager::Dispatch,進(jìn)入HRilCall中的ProcessCallRequest,然后根據(jù)HREQ_CALL_DIAL在函數(shù)指針數(shù)組reqMemberFuncMap_找到了處理函數(shù)HRilCall::Dial,然后處理邏輯變到了callFuncs_->Dial中。
8、RIL適配層(RIL Adapter)中的處理流程
要知道callFuncs_->Dial的最終位置,就要查找callFuncs_的賦值流程, HRilCall::RegisterCallFuncs上層調(diào)用是
HRilManager::RegisterCallFuncs再上層是HRilRegOps。
HRilRegOps在LoadVendor中調(diào)用,這又涉及到了modem的加載機(jī)制,具體廠商modem處理的部分是通過(guò)so加載的方式引入的。
通過(guò)打開so文件并建立函數(shù)的對(duì)應(yīng)關(guān)系,最終調(diào)用的at命令的具體實(shí)現(xiàn)部分。
so的代碼目錄在vendor目錄下,通過(guò)成員為函數(shù)指針的結(jié)構(gòu)體建立關(guān)聯(lián)性。
也就是callFuncs_->Dial在so中的處理函數(shù)是ReqDial,在這里邊組裝了具體的at命令 ,撥打電話的命令是ATD,GenerateCommand(cmd, MAX_CMD_LENGTH, “ATD%s%s;”, pDial->address, clir)。
最終通過(guò)WriteATCommand函數(shù)寫入到了at命令的通道,通道就是具體的modem模塊與主處理器的硬件連接了。
也就是當(dāng)前代碼中的usb通道。