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