天天看點

Openharmony撥打電話全流程介紹

1 背景介紹

3.1版本标準系統增加了通話相關的聯系人應用,來電應用等,在系統服務層面電話相關功能也比較完善,相關modem子產品目前從代碼中看到有美格智能的slm790和紫光展銳的子產品,之前介紹過鴻蒙電話服務子系統功能劃分介紹,隻是對官方文檔的介紹,可以通過這個文檔先去了解一下各個功能子產品。今天從上到下分析下代碼調用流程,以撥打電話為例介紹鴻蒙電話子系統的各個部分。電話服務子系統的在/base/telephony目錄下,大概有700多個檔案,11萬多行代碼。

Openharmony撥打電話全流程介紹

2 應用層js代碼介紹

應用層撥打電話的應用是聯系人,聯系人應用的通話記錄,聯系人檢視,撥号盤和收藏都有對撥電話的調用。

Openharmony撥打電話全流程介紹

最終調用的是app.js中的call函數,此函數調用的是@ohos.telephony.call中的dial方法。

Openharmony撥打電話全流程介紹

應用層隻是調用電話架構層的api,這個api就是@ohos.telephony.call提供的。

3 撥打電話NAPI實作介紹

應用層調用的是js函數,而電話服務層是c++語言實作的,二者之間的橋梁就是通過NAPI實作的,有關NAPI介紹請參照這幾篇文章源碼解析之JavaScript API架構(NAPI)。簡單來說js的函數在c++層都有對應的實作,它們之間是一一對應的關系,比如js的dial對應的是c++的DialCall,相關代碼如下,這部分代碼在通話管理子產品

Openharmony撥打電話全流程介紹

NapiCallManager::DialCall函數中調用的函數是

HandleAsyncWork(env, asyncContext, "DialCall", NativeDialCall, NativeDialCallBack);

Openharmony撥打電話全流程介紹

之後跳轉到了CallManagerClient中的DialCall,然後是CallManagerProxy::DialCall,如下:

Openharmony撥打電話全流程介紹
Openharmony撥打電話全流程介紹

3 如何從CallManagerServiceProxy到CallManagerServiceStub

到CallManagerProxy::DialCall中後代碼突然不清晰了,callManagerServicePtr_是什麼,它的DialCall在哪裡,順藤摸瓜,它的位置如下:

Openharmony撥打電話全流程介紹

SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager()和

managerPtr->GetSystemAbility(systemAbilityId_)是了解下一步調用位置的關鍵。

這裡涉及到了另外一個知識點,就是程序通信,這裡使用了ipc機制,可以檢視官方文檔的介紹,

在目錄foundation/comminucotion下的ipc下有readme文檔,貼一張原圖:

Openharmony撥打電話全流程介紹

大體意思是proxy通過samgr也就是SystemAbilityManager,去調用跨程序的Stub中的函數,代碼層面可以通過systemAbilityId_和接口類去定位函數調用的對應關系,這裡的abilityid是TELEPHONY_CALL_MANAGER_SYS_ABILITY_ID,接口類是ICallManagerService,通過查找定位到了CallManagerServiceProxy和CallManagerServiceStub。

函數調用就是從CallManagerServiceProxy::DialCall過渡到了CallManagerServiceStub::OnDialCall。

4 從CallControlManager::DialCall到 蜂窩通話(cellular_call)子產品

CallManagerServiceStub::OnDialCall中調用到了CallControlManager::DialCall,然後又走到了

CallRequestHandlerService::DialCall(),這裡調用了一個發送事件函數,這是一種線程異步處理機智可以看這篇文章,隻要有發就有收,我們找到收事件的地方。

Openharmony撥打電話全流程介紹

對應關系在如下位置,由此找到了函數CallRequestHandler::DialCallEvent。

Openharmony撥打電話全流程介紹

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

Openharmony撥打電話全流程介紹

我們走CallRequestProcess::DialRequest分支,然後走到了CellularCallIpcInterfaceProxy::Dial

在這裡我們又遇到了ipc,同樣的方法此時id是TELEPHONY_CELLULAR_CALL_SYS_ABILITY_ID,

找到stub函數位置是CellularCallStub::Dial,此時已經到了蜂窩通話子產品目錄。

Openharmony撥打電話全流程介紹

5 從蜂窩通話(cellular_call)到 核心服務(core_service)

CellularCallStub::Dial直接調用的是CSControl::Dial

Openharmony撥打電話全流程介紹

在這裡又出現了類型判斷,判斷手機網絡制式是gsm還是cdma,了解通信行業的都知道gsm和cdma是2G時代的兩種制式标準,一個是歐洲主導的,一個是高通主導的,扯得有點遠,繼續看代碼。

二者最終調用的是CSControl::EncapsulateDialCommon,然後CellularCallConnectionCS::DialRequest。

然後進入到了核心服務子產品

Openharmony撥打電話全流程介紹

然後是TelRilManager::Dial和TelRilCall::Dial

6 從核心服務(core_service)到 RIL适配層(RIL Adapter)

TelRilCall::Dial中調用了TelRilBase基類的SendBufferEvent(HREQ_CALL_DIAL, wData)函數代碼如下

Openharmony撥打電話全流程介紹

cellularRadio_這個成員的初始化實在TelRilManager中

Openharmony撥打電話全流程介紹

這又涉及到了另外一個知識點驅動相關看這篇OpenHarmony HDF HDI基礎能力分析與使用,對modem的操作在RIL适配層被當做了驅動服務來使用的,SendRequest就是對驅動的異步調用,在驅動中的函數RilAdapterDispatch負責對SendRequest的接收處理

Openharmony撥打電話全流程介紹

而這個處理函數是驅動加載時運作起來的

Openharmony撥打電話全流程介紹

RilAdapterDispatch中的函數DispatchRequest位于HRilManager中,然後調用DispatchModule

繼續調用HRilManager::Dispatch,進入HRilCall中的ProcessCallRequest,然後根據HREQ_CALL_DIAL在函數指針數組reqMemberFuncMap_找到了處理函數HRilCall::Dial,然後處理邏輯變到了callFuncs_->Dial中

Openharmony撥打電話全流程介紹

7 RIL适配層(RIL Adapter)中的處理流程

要知道callFuncs_->Dial的最終位置,就要查找callFuncs_的指派流程, HRilCall::RegisterCallFuncs上層調用是

HRilManager::RegisterCallFuncs再上層是HRilRegOps

Openharmony撥打電話全流程介紹

HRilRegOps在LoadVendor中調用,這又涉及到了modem的加載機制,具體廠商modem處理的部分是通過so加載的方式引入的,

通過打開so檔案并建立函數的對應關系,最終調用的at指令的具體實作部分。

Openharmony撥打電話全流程介紹

so的代碼目錄在vendor目錄下,通過成員為函數指針的結構體建立關聯性

Openharmony撥打電話全流程介紹

也就是callFuncs_->Dial在so中的處理函數是ReqDial,在這裡邊組裝了具體的at指令 ,撥打電話的指令是ATD,GenerateCommand(cmd, MAX_CMD_LENGTH, "ATD%s%s;", pDial->address, clir);

最終通過WriteATCommand函數寫入到了at指令的通道,通道就是具體的modem子產品與主處理器的硬體連接配接了

Openharmony撥打電話全流程介紹

也就是目前代碼中的usb通道

Openharmony撥打電話全流程介紹

繼續閱讀