3

Openharmony拨打电话全流程介绍-51CTO.COM

 2 years ago
source link: https://os.51cto.com/article/708535.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Openharmony拨打电话全流程介绍-51CTO.COM

Openharmony拨打电话全流程介绍
作者:鸿蒙开发 2022-05-10 11:02:02
今天从上到下分析下代码调用流程,以拨打电话为例介绍鸿蒙电话子系统的各个部分。电话服务子系统的在/base/telephony目录下,大概有700多个文件,11万多行代码。

f5b7b4075afed130aa72390d5bbfb43f911eb8.png

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

​https://ost.51cto.com​

1、背景介绍

3.1版本标准系统增加了通话相关的联系人应用,来电应用等,在系统服务层面电话相关功能也比较完善,相关modem模块目前从代码中看到有美格智能的slm790和紫光展锐的模块,之前介绍过​​鸿蒙电话服务子系统功能划分介绍​​,只是对官方文档的介绍,可以通过这个文档先去了解一下各个功能模块。今天从上到下分析下代码调用流程,以拨打电话为例介绍鸿蒙电话子系统的各个部分。电话服务子系统的在/base/telephony目录下,大概有700多个文件,11万多行代码。

a657c32272b76524b884765bbe63da36bbec74.png

2、应用层js代码介绍

应用层拨打电话的应用是联系人,联系人应用的通话记录,联系人查看,拨号盘和收藏都有对拨电话的调用。

b7bf8c943d211c5de340094f18ad2f0f329117.png

最终调用的是app.js中的call函数,此函数调用的是@ohos.telephony.call中的dial方法。

263b317519df2ca147f7389f8ae21c8cb38244.png

应用层只是调用电话框架层的api,这个api就是@ohos.telephony.call提供的。

3、拨打电话NAPI实现介绍

应用层调用的是js函数,而电话服务层是c语言实现的,二者之间的桥梁就是通过NAPI实现的,有关NAPI介绍请参照这几篇文章源码解析之JavaScript API框架(NAPI)。简单来说js的函数在c层都有对应的实现,它们之间是一一对应的关系,比如js的dial对应的是c++的DialCall,相关代码如下,这部分代码在通话管理模块。

014c54e15a3ab0c975b825e2b1eebd27ebbf54.png

NapiCallManager::DialCall函数中调用的函数是。

HandleAsyncWork(env, asyncContext, “DialCall”, NativeDialCall, NativeDialCallBack)。

490e01e768b0339d2649081c301cfb18ea3c64.png

之后跳转到了CallManagerClient中的DialCall,然后是CallManagerProxy::DialCall,如下:

68198c139f12f621d392496232a6cc9bde0574.png

f4cbf3b01428f347481902de83d71b5e20d1b7.png

4、如何从CallManagerServiceProxy到CallManagerServiceStub

到CallManagerProxy::DialCall中后代码突然不清晰了,callManagerServicePtr_是什么,它的DialCall在哪里,顺藤摸瓜,它的位置如下:

35a71ea80c8ca44126f749f67a51bd4595dc05.png

SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager()和managerPtr->GetSystemAbility(systemAbilityId_)是理解下一步调用位置的关键。

这里涉及到了另外一个知识点,就是进程通信,这里使用了ipc机制,可以查看官方文档的介绍。

在目录foundation/comminucotion下的ipc下有readme文档,贴一张原图:

e5aa64667cc388de294307b7ea99a0a4ca5f67.png

大体意思是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(),这里调用了一个发送事件函数,这是一种线程异步处理机智可以看这篇文章,只要有发就有收,我们找到收事件的地方。

d47d54a53d1cebe0ddb827e6e6cdec49bd313e.png

对应关系在如下位置,由此找到了函数CallRequestHandler::DialCallEvent。

933e6789014ab76952977067339d10a1190f8c.png

CallRequestHandler::DialCallEvent中有针对类型的判断:

17daa42755cbe6570c74532e028b137eab178c.png

我们走CallRequestProcess::DialRequest分支,然后走到了CellularCallIpcInterfaceProxy::Dial。

在这里我们又遇到了ipc,同样的方法此时id是TELEPHONY_CELLULAR_CALL_SYS_ABILITY_ID。

找到stub函数位置是CellularCallStub::Dial,此时已经到了蜂窝通话模块目录。

648567d0995ff335a183923e3409dc2dd80a4f.png

6、从蜂窝通话(cellular_call)到 核心服务(core_service)

CellularCallStub::Dial直接调用的是CSControl::Dial。

14705a564c43ff447d13921a4dbc3abc0d0c2a.png

在这里又出现了类型判断,判断手机网络制式是gsm还是cdma,了解通信行业的都知道gsm和cdma是2G时代的两种制式标准,一个是欧洲主导的,一个是高通主导的,扯得有点远,继续看代码。

二者最终调用的是CSControl::EncapsulateDialCommon,然后CellularCallConnectionCS::DialRequest。

然后进入到了核心服务模块。

85123f04307a91cc5620283432f141bd267274.png

然后是TelRilManager::Dial和TelRilCall::Dial。

7、从核心服务(core_service)到 RIL适配层(RIL Adapter)

TelRilCall::Dial中调用了TelRilBase基类的SendBufferEvent(HREQ_CALL_DIAL, wData)函数代码如下:

86389a500e08495edc0949b1eb5be4c1ef1297.png

cellularRadio_这个成员的初始化实在TelRilManager中。

58b1fd587d1eef5610c7664cea7925eb0a0346.png

这又涉及到了另外一个知识点驱动相关看这篇OpenHarmony HDF HDI基础能力分析与使用,对modem的操作在RIL适配层被当做了驱动服务来使用的,SendRequest就是对驱动的异步调用,在驱动中的函数RilAdapterDispatch负责对SendRequest的接收处理。

36ed6a792bf95caac4f493f891958d5848a289.png

而这个处理函数是驱动加载时运行起来的。

61a329528e8b9fc61947325d8b65f9f9b44ef3.png

RilAdapterDispatch中的函数DispatchRequest位于HRilManager中,然后调用DispatchModule。

继续调用HRilManager::Dispatch,进入HRilCall中的ProcessCallRequest,然后根据HREQ_CALL_DIAL在函数指针数组reqMemberFuncMap_找到了处理函数HRilCall::Dial,然后处理逻辑变到了callFuncs_->Dial中。

d9914f9161a40a79e7c344ee1e3bdeb8d4873d.png

8、RIL适配层(RIL Adapter)中的处理流程

要知道callFuncs_->Dial的最终位置,就要查找callFuncs_的赋值流程, HRilCall::RegisterCallFuncs上层调用是

HRilManager::RegisterCallFuncs再上层是HRilRegOps。

b80fe2c43571681daee511a492b0a55ce94322.png

HRilRegOps在LoadVendor中调用,这又涉及到了modem的加载机制,具体厂商modem处理的部分是通过so加载的方式引入的。

通过打开so文件并建立函数的对应关系,最终调用的at命令的具体实现部分。

d63efe003fb892aece8835fe66e3a4b45a5fcd.png

so的代码目录在vendor目录下,通过成员为函数指针的结构体建立关联性。

38bdbe09375f14b82df471e5db5ff564f2d36a.png

也就是callFuncs_->Dial在so中的处理函数是ReqDial,在这里边组装了具体的at命令 ,拨打电话的命令是ATD,GenerateCommand(cmd, MAX_CMD_LENGTH, “ATD%s%s;”, pDial->address, clir)。

最终通过WriteATCommand函数写入到了at命令的通道,通道就是具体的modem模块与主处理器的硬件连接了。

3601cbe310e9a8e71e6691c6f8c8fb7bac16c8.png

也就是当前代码中的usb通道。

88c50b1389e2b0f140f4286aba5e8226292758.png

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

​https://ost.51cto.com​​。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK