Openharmony撥打電話全流程介紹

??想了解更多關(guān)于開源的內(nèi)容,請訪問:??
1、背景介紹
3.1版本標(biāo)準(zhǔn)系統(tǒng)增加了通話相關(guān)的聯(lián)系人應(yīng)用,來電應(yīng)用等,在系統(tǒng)服務(wù)層面電話相關(guān)功能也比較完善,相關(guān)modem模塊目前從代碼中看到有美格智能的slm790和紫光展銳的模塊,之前介紹過??鴻蒙電話服務(wù)子系統(tǒng)功能劃分介紹??,只是對官方文檔的介紹,可以通過這個文檔先去了解一下各個功能模塊。今天從上到下分析下代碼調(diào)用流程,以撥打電話為例介紹鴻蒙電話子系統(tǒng)的各個部分。電話服務(wù)子系統(tǒng)的在/base/telephony目錄下,大概有700多個文件,11萬多行代碼。

2、應(yīng)用層js代碼介紹
應(yīng)用層撥打電話的應(yīng)用是聯(lián)系人,聯(lián)系人應(yīng)用的通話記錄,聯(lián)系人查看,撥號盤和收藏都有對撥電話的調(diào)用。

最終調(diào)用的是app.js中的call函數(shù),此函數(shù)調(diào)用的是@ohos.telephony.call中的dial方法。

應(yīng)用層只是調(diào)用電話框架層的api,這個api就是@ohos.telephony.call提供的。
3、撥打電話NAPI實現(xiàn)介紹
應(yīng)用層調(diào)用的是js函數(shù),而電話服務(wù)層是c語言實現(xiàn)的,二者之間的橋梁就是通過NAPI實現(xiàn)的,有關(guān)NAPI介紹請參照這幾篇文章源碼解析之JavaScript API框架(NAPI)。簡單來說js的函數(shù)在c層都有對應(yīng)的實現(xiàn),它們之間是一一對應(yīng)的關(guān)系,比如js的dial對應(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)鍵。
這里涉及到了另外一個知識點,就是進(jìn)程通信,這里使用了ipc機(jī)制,可以查看官方文檔的介紹。
在目錄foundation/comminucotion下的ipc下有readme文檔,貼一張原圖:

大體意思是proxy通過samgr也就是SystemAbilityManager,去調(diào)用跨進(jìn)程的Stub中的函數(shù),代碼層面可以通過systemAbilityId_和接口類去定位函數(shù)調(diào)用的對應(yīng)關(guān)系,這里的abilityid是TELEPHONY_CALL_MANAGER_SYS_ABILITY_ID,接口類是ICallManagerService,通過查找定位到了CallManagerServiceProxy和CallManagerServiceStub。
函數(shù)調(diào)用就是從CallManagerServiceProxy::DialCall過渡到了CallManagerServiceStub::OnDialCall。
5、從CallControlManager::DialCall到 蜂窩通話(cellular_call)模塊
CallManagerServiceStub::OnDialCall中調(diào)用到了CallControlManager::DialCall,然后又走到了。
CallRequestHandlerService::DialCall(),這里調(diào)用了一個發(fā)送事件函數(shù),這是一種線程異步處理機(jī)智可以看這篇文章,只要有發(fā)就有收,我們找到收事件的地方。

對應(yīng)關(guān)系在如下位置,由此找到了函數(shù)CallRequestHandler::DialCallEvent。

CallRequestHandler::DialCallEvent中有針對類型的判斷:

我們走CallRequestProcess::DialRequest分支,然后走到了CellularCallIpcInterfaceProxy::Dial。
在這里我們又遇到了ipc,同樣的方法此時id是TELEPHONY_CELLULAR_CALL_SYS_ABILITY_ID。
找到stub函數(shù)位置是CellularCallStub::Dial,此時已經(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時代的兩種制式標(biāo)準(zhǔn),一個是歐洲主導(dǎo)的,一個是高通主導(dǎo)的,扯得有點遠(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_這個成員的初始化實在TelRilManager中。

這又涉及到了另外一個知識點驅(qū)動相關(guān)看這篇OpenHarmony HDF HDI基礎(chǔ)能力分析與使用,對modem的操作在RIL適配層被當(dāng)做了驅(qū)動服務(wù)來使用的,SendRequest就是對驅(qū)動的異步調(diào)用,在驅(qū)動中的函數(shù)RilAdapterDispatch負(fù)責(zé)對SendRequest的接收處理。

而這個處理函數(shù)是驅(qū)動加載時運(yùn)行起來的。

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處理的部分是通過so加載的方式引入的。
通過打開so文件并建立函數(shù)的對應(yīng)關(guān)系,最終調(diào)用的at命令的具體實現(xiàn)部分。

so的代碼目錄在vendor目錄下,通過成員為函數(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)。
最終通過WriteATCommand函數(shù)寫入到了at命令的通道,通道就是具體的modem模塊與主處理器的硬件連接了。

也就是當(dāng)前代碼中的usb通道。
















 
 
 






 
 
 
 