0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一文详解OpenHarmony软总线

OpenHarmony技术社区 来源:HarmonyOS技术社区 作者:HarmonyOS技术社区 2022-03-30 08:38 次阅读

本次说明可能侧重在标准系统之上。软总线依旧采用鸿蒙经典的 proxy - stub 架构,接口类 ISoftBusServer,ISoftBusClient。

一般来说,一些服务就一个接口类,为什么软总线会有两个呢?我们再看看继承关系。

和 ISoftBusServer 相关的有:

一文详解OpenHarmony软总线

类似的 ISoftBusClient:

一文详解OpenHarmony软总线

从上面的图中可以看出,一个 stub 甚至对应几个 proxy,看下代码,可以看到就是 proxy 就是解耦,更加的职责清晰。

我们通过观察目录结构和对应的代码接口进行查看,便不难看出一二。

先看 ISoftBusClient 接口类:
namespaceOHOS{
classISoftBusClient:publicIRemoteBroker{
public:
virtual~ISoftBusClient()=default;

virtualvoidOnDeviceFound(constDeviceInfo*device)=0;
virtualvoidOnDiscoverFailed(intsubscribeId,intfailReason)=0;
virtualvoidOnDiscoverySuccess(intsubscribeId)=0;
virtualvoidOnPublishSuccess(intpublishId)=0;
virtualvoidOnPublishFail(intpublishId,intreason)=0;
virtualint32_tOnChannelOpened(constchar*sessionName,constChannelInfo*channel)=0;
virtualint32_tOnChannelOpenFailed(int32_tchannelId,int32_tchannelType)=0;
virtualint32_tOnChannelLinkDown(constchar*networkId,int32_trouteType)=0;
virtualint32_tOnChannelMsgReceived(int32_tchannelId,int32_tchannelType,constvoid*data,
uint32_tlen,int32_ttype)=0;
virtualint32_tOnChannelClosed(int32_tchannelId,int32_tchannelType)=0;
virtualint32_tOnChannelQosEvent(int32_tchannelId,int32_tchannelType,int32_teventId,int32_ttvCount,
constQosTv*tvList)=0;
virtualint32_tOnJoinLNNResult(void*addr,uint32_taddrTypeLen,constchar*networkId,intretCode)=0;
virtualint32_tOnLeaveLNNResult(constchar*networkId,intretCode)=0;
virtualint32_tOnNodeOnlineStateChanged(boolisOnline,void*info,uint32_tinfoTypeLen)=0;
virtualint32_tOnNodeBasicInfoChanged(void*info,uint32_tinfoTypeLen,int32_ttype)=0;
virtualint32_tOnTimeSyncResult(constvoid*info,uint32_tinfoTypeLen,int32_tretCode)=0;
virtualvoidOnPublishLNNResult(int32_tpublishId,int32_treason);
virtualvoidOnRefreshLNNResult(int32_trefreshId,int32_treason);
virtualvoidOnRefreshDeviceFound(constvoid*device,uint32_tdeviceLen);

public:
DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.ISoftBusClient");
};
}//namespaceOHOS
其中的接口方法就是主要的 SDK 中的对外接口。

再看 ISoftBusServer:

namespaceOHOS{
classISoftBusServer:publicIRemoteBroker{
public:
virtual~ISoftBusServer()=default;

virtualint32_tStartDiscovery(constchar*pkgName,constSubscribeInfo*info)=0;
virtualint32_tStopDiscovery(constchar*pkgName,intsubscribeId)=0;
virtualint32_tPublishService(constchar*pkgName,constPublishInfo*info)=0;
virtualint32_tUnPublishService(constchar*pkgName,intpublishId)=0;
virtualint32_tSoftbusRegisterService(constchar*clientPkgName,constsptr&object)=0;

virtualint32_tCreateSessionServer(constchar*pkgName,constchar*sessionName)=0;
virtualint32_tRemoveSessionServer(constchar*pkgName,constchar*sessionName)=0;
virtualint32_tOpenSession(constSessionParam*param,TransInfo*info)=0;
virtualint32_tOpenAuthSession(constchar*sessionName,constConnectionAddr*addrInfo)=0;
virtualint32_tNotifyAuthSuccess(intchannelId)=0;
virtualint32_tCloseChannel(int32_tchannelId,int32_tchannelType)=0;
virtualint32_tSendMessage(int32_tchannelId,int32_tchannelType,
constvoid*data,uint32_tlen,int32_tmsgType)=0;
virtualint32_tJoinLNN(constchar*pkgName,void*addr,uint32_taddrTypeLen)=0;
virtualint32_tLeaveLNN(constchar*pkgName,constchar*networkId)=0;
virtualint32_tGetAllOnlineNodeInfo(constchar*pkgName,void**info,uint32_tinfoTypeLen,int*infoNum)=0;
virtualint32_tGetLocalDeviceInfo(constchar*pkgName,void*info,uint32_tinfoTypeLen)=0;
virtualint32_tGetNodeKeyInfo(constchar*pkgName,constchar*networkId,intkey,unsignedchar*buf,
uint32_tlen)=0;
virtualint32_tStartTimeSync(constchar*pkgName,constchar*targetNetworkId,int32_taccuracy,
int32_tperiod)=0;
virtualint32_tStopTimeSync(constchar*pkgName,constchar*targetNetworkId)=0;
virtualint32_tQosReport(int32_tchannelId,int32_tchanType,int32_tappType,int32_tquality)=0;
virtualint32_tPublishLNN(constchar*pkgName,constvoid*info,uint32_tinfoTypeLen);
virtualint32_tStopPublishLNN(constchar*pkgName,int32_tpublishId);
virtualint32_tRefreshLNN(constchar*pkgName,constvoid*info,uint32_tinfoTypeLen);
virtualint32_tStopRefreshLNN(constchar*pkgName,int32_trefreshId);
virtualint32_tActiveMetaNode(constMetaNodeConfigInfo*info,char*metaNodeId);
virtualint32_tDeactiveMetaNode(constchar*metaNodeId);
virtualint32_tGetAllMetaNodeInfo(MetaNodeInfo*info,int32_t*infoNum);

public:
DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.ISoftBusServer");
};

包括发现设备,发布服务,相当于这是系统自启动的一个服务。

解析一次调用链

对于 proxy - client 架构,一般来说就是 client 调用 sendRequest,server 便会调用 OnRemoteRequest。

我们直接从 stub 的方法入手分析下:

SoftBusClientStub::SoftBusClientStub()
{
memberFuncMap_[CLIENT_DISCOVERY_DEVICE_FOUND]=
&SoftBusClientStub::OnDeviceFoundInner;
memberFuncMap_[CLIENT_DISCOVERY_SUCC]=
&SoftBusClientStub::OnDiscoverySuccessInner;
memberFuncMap_[CLIENT_DISCOVERY_FAIL]=
&SoftBusClientStub::OnDiscoverFailedInner;
memberFuncMap_[CLIENT_PUBLISH_SUCC]=
&SoftBusClientStub::OnPublishSuccessInner;
memberFuncMap_[CLIENT_PUBLISH_FAIL]=
&SoftBusClientStub::OnPublishFailInner;
memberFuncMap_[CLIENT_ON_CHANNEL_OPENED]=
&SoftBusClientStub::OnChannelOpenedInner;
memberFuncMap_[CLIENT_ON_CHANNEL_OPENFAILED]=
&SoftBusClientStub::OnChannelOpenFailedInner;
memberFuncMap_[CLIENT_ON_CHANNEL_LINKDOWN]=
&SoftBusClientStub::OnChannelLinkDownInner;
memberFuncMap_[CLIENT_ON_CHANNEL_CLOSED]=
&SoftBusClientStub::OnChannelClosedInner;
memberFuncMap_[CLIENT_ON_CHANNEL_MSGRECEIVED]=
&SoftBusClientStub::OnChannelMsgReceivedInner;
memberFuncMap_[CLIENT_ON_CHANNEL_QOSEVENT]=

这里我们看到是使用不同的 CODE 做分发。但是对外的接口都是 c 接口,c++ 接口中没有任何内容存储信息这是为啥?这是为了兼容标准系统和其他系统。

信息存储再统一的结构里面,然后根据不同的系统编译不同的 .c 或者 .cpp 文件。

咱们以 joinLNN 为例:

int32_tJoinLNN(constchar*pkgName,ConnectionAddr*target,OnJoinLNNResultcb)
{
if(pkgName==NULL||target==NULL||cb==NULL){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"fail:paramsareNULL!");
returnSOFTBUS_INVALID_PARAM;
}
if(CommonInit(pkgName)!=SOFTBUS_OK){
returnSOFTBUS_INVALID_PARAM;
}
returnJoinLNNInner(pkgName,target,cb);
}

实际调用的是 joinLNNInner:

int32_tJoinLNNInner(constchar*pkgName,ConnectionAddr*target,OnJoinLNNResultcb)
{
int32_trc;

if(!g_busCenterClient.isInit){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"fail:joinlnnnotinit");
returnSOFTBUS_NO_INIT;
}
if(SoftBusMutexLock(&g_busCenterClient.lock)!=0){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"fail:lockjoinlnncblistinjoin");
}
rc=SOFTBUS_ERR;
do{
if(FindJoinLNNCbItem(target,cb)!=NULL){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"fail:joinrequestalreadyexist");
rc=SOFTBUS_ALREADY_EXISTED;
break;
}
rc=ServerIpcJoinLNN(pkgName,target,sizeof(*target));
if(rc!=SOFTBUS_OK){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"fail:requestjoinlnn");
}else{
rc=AddJoinLNNCbItem(target,cb);
}
}while(false);
if(SoftBusMutexUnlock(&g_busCenterClient.lock)!=0){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"fail:unlockjoinlnncblistinjoin");
}
returnrc;
}

先做了一些初始化的操作,查找当前节点是否存在。然后 ServerIpcJoinLNN 通信就是使用的 proxy-stub 侧的代码。

int32_tServerIpcJoinLNN(constchar*pkgName,void*addr,unsignedintaddrTypeLen)
{
if(g_serverProxy==nullptr){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"ServerIpcJoinLNNg_serverProxyisnullptr!
");
returnSOFTBUS_ERR;
}
intret=g_serverProxy->JoinLNN(pkgName,addr,addrTypeLen);
if(ret!=0){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"ServerIpcJoinLNNfailed!
");
returnret;
}
returnSOFTBUS_OK;
}

这里的关键就是 g_serverProxy->JoinLNN(pkgName,addr,addrTypeLen);

实际调用的是:
int32_tBusCenterServerProxy::JoinLNN(constchar*pkgName,void*addr,uint32_taddrTypeLen)
{
if(pkgName==nullptr||addr==nullptr){
returnSOFTBUS_ERR;
}
sptrremote=GetSystemAbility();
if(remote==nullptr){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"remoteisnullptr!");
returnSOFTBUS_ERR;
}

MessageParceldata;
if(!data.WriteCString(pkgName)){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"JoinLNNwriteclientnamefailed!");
returnSOFTBUS_ERR;
}
if(!data.WriteUint32(addrTypeLen)){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"JoinLNNwriteaddrtypelengthfailed!");
returnSOFTBUS_ERR;
}
if(!data.WriteRawData(addr,addrTypeLen)){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"JoinLNNwriteaddrfailed!");
returnSOFTBUS_ERR;
}
MessageParcelreply;
MessageOptionoption;
if(remote->SendRequest(SERVER_JOIN_LNN,data,reply,option)!=0){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"JoinLNNsendrequestfailed!");
returnSOFTBUS_ERR;
}
int32_tserverRet=0;
if(!reply.ReadInt32(serverRet)){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"JoinLNNreadserverRetfailed!");
returnSOFTBUS_ERR;
}
returnserverRet;
}

再看对应 sub 中 SERVER_JOIN_LNN 值去调用下面这个方法:

int32_tSoftBusServerStub::JoinLNNInner(MessageParcel&data,MessageParcel&reply)
{
constchar*clientName=data.ReadCString();
if(clientName==nullptr){
SoftBusLog(SOFTBUS_LOG_COMM,SOFTBUS_LOG_ERROR,"SoftbusJoinLNNInnerreadclientNamefailed!");
returnSOFTBUS_ERR;
}
uint32_taddrTypeLen;
if(!data.ReadUint32(addrTypeLen)){
SoftBusLog(SOFTBUS_LOG_COMM,SOFTBUS_LOG_ERROR,"SoftbusJoinLNNInnerreadaddrtypelengthfailed!");
returnSOFTBUS_ERR;
}
void*addr=(void*)data.ReadRawData(addrTypeLen);
if(addr==nullptr){
SoftBusLog(SOFTBUS_LOG_COMM,SOFTBUS_LOG_ERROR,"SoftbusJoinLNNInnerreadaddrfailed!");
returnSOFTBUS_ERR;
}
int32_tretReply=JoinLNN(clientName,addr,addrTypeLen);
if(!reply.WriteInt32(retReply)){
SoftBusLog(SOFTBUS_LOG_COMM,SOFTBUS_LOG_ERROR,"SoftbusJoinLNNInnerwritereplyfailed!");
returnSOFTBUS_ERR;
}
returnSOFTBUS_OK;
}

可以看到显示读数据,然后调用 JoinLNN,你发现 stub 这个方法为空,但是要注意到这个方法是一个虚函数。

去查看它的子类 SoftBusServer:

int32_tSoftBusServer::JoinLNN(constchar*pkgName,void*addr,uint32_taddrTypeLen)
{
returnLnnIpcServerJoin(pkgName,addr,addrTypeLen);
}

所以真正调用的是 LnnIpcServerJoin,我们看下他到底做了什么,这是真正的业务逻辑所在。

int32_tLnnIpcServerJoin(constchar*pkgName,void*addr,uint32_taddrTypeLen)
{
ConnectionAddr*connAddr=(ConnectionAddr*)addr;

(void)addrTypeLen;
if(pkgName==nullptr||connAddr==nullptr){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"parametersarenullptr!
");
returnSOFTBUS_INVALID_PARAM;
}
std::lock_guard<std::mutex>autoLock(g_lock);
if(IsRepeatJoinLNNRequest(pkgName,connAddr)){
SoftBusLog(SOFTBUS_LOG_LNN,SOFTBUS_LOG_ERROR,"repeatjoinlnnrequestfrom:%s",pkgName);
returnSOFTBUS_ALREADY_EXISTED;
}
int32_tret=LnnServerJoin(connAddr);
if(ret==SOFTBUS_OK){
ret=AddJoinLNNInfo(pkgName,connAddr);
}
returnret;
}

看一下,主要是有几个部分,第一查看参数有效性,第二是不是重复节点,使用连接地址创建连接,使用包名和地址建立映射。具体的感兴趣的小伙伴可以去查看一下。

原文标题:OpenHarmony软总线架构分析

文章出处:【微信公众号:HarmonyOS技术社区】欢迎添加关注!文章转载请注明出处。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    7637

    浏览量

    148462
  • 架构
    +关注

    关注

    1

    文章

    484

    浏览量

    25200
  • OpenHarmony
    +关注

    关注

    23

    文章

    3273

    浏览量

    15159

原文标题:OpenHarmony软总线架构分析

文章出处:【微信号:gh_834c4b3d87fe,微信公众号:OpenHarmony技术社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    OpenHarmony分布式总线流程分析

    OpenHarmony分布式总线流程分析,大神总结,大家可以下载去学习了~.~
    发表于 11-19 15:56

    带你看懂分布式总线在家庭场景的应用

    终端融为体,形成超级终端,为消费者带来全场景智慧生活新体验。如何让各种不同的设备融合为体,形成超级终端呢?这就需要分布式总线来实现。分布式
    发表于 01-06 11:32

    OpenHarmony总线】——总线启动流程预览

    、TransServerInit 传输3、AuthInit 认证4、DiscServerInit 发现,包含了Coap的初始化,具体怎么实现组网的还需要研究下5、BusCenterServerInit 总线组网&网络拓扑结构
    发表于 01-10 15:37

    OpenHarmony总线】——告别代码,让Openharmony总线测试用例跑起来!

    目的:openharmony 总线代码过于庞大,而且其中有很多地方的功能并没完善,走读代码应该是种比较痛苦的方法。此次介绍如何使用
    发表于 01-10 15:40

    OpenHarmony总线】——连接模块分析

    设备通过公共通信干线来进行通信,设备需要具备收发数据功能。openharmony 总线需要将不同设备整合到起,由于不同的设备通信存在差异,如wifi与蓝牙之间通信存在差异,
    发表于 01-11 16:16

    OpenHarmony总线】——总线启动流程预览

    、TransServerInit 传输3、AuthInit 认证4、DiscServerInit 发现,包含了Coap的初始化,具体怎么实现组网的还需要研究下5、BusCenterServerInit 总线组网&网络拓扑结构
    发表于 01-26 11:53

    OpenHarmony总线】——告别代码,让Openharmony总线测试用例跑起来!

    目的:openharmony 总线代码过于庞大,而且其中有很多地方的功能并没完善,走读代码应该是种比较痛苦的方法。此次介绍如何使用
    发表于 01-26 11:53

    OpenHarmony总线】——连接模块分析

    设备通过公共通信干线来进行通信,设备需要具备收发数据功能。openharmony 总线需要将不同设备整合到起,由于不同的设备通信存在差异,如wifi与蓝牙之间通信存在差异,
    发表于 01-26 11:53

    OpenHarmony共同成长:年的历程和成果展示

    OpenHarmony实现万物互联/万物智联的基石。因为总线个非常庞大且复杂的系统,这几个月来我直尝试尽可能深入地去理解它,但是技
    发表于 03-30 08:52

    了解OpenHarmony开源项目

    hdc;提供了性能跟踪能力和接口;提供了性能调优框架,旨在为开发者提供套性能调优平台,可以用来分析内存、性能等问题。标准系统分布式总线分布式
    发表于 05-06 14:59

    你玩过轻量系统总线应用吗?

    Release(以下简称“OpenHarmony”)版本的轻量系统总线能力,将智能燃气检测设备和智能窗户通风设备组成个轻量级分布式网络,实现设备之间的相互控制。原理图如下:当家中
    发表于 07-14 10:42

    国际工业中控屏通过OpenHarmony兼容性测评

    、协同联动的重要保障。中国际积极参与OpenHarmony社区生态建设,此次ASTS1501工业中控屏设备通过测评进步丰富了基于OpenHarmony的工业智能终端生态,助力
    发表于 12-23 11:25

    国际电子哨兵终端通过OpenHarmony兼容性测评

    、功能优化、应用场景等方面推进研发创新,为电子哨兵设备和OpenHarmony智能终端产业的发展贡献自己的份力量。未来,中国际将依托智能化终端设备矩阵,以OpenHarmony重点
    发表于 01-11 11:05

    CAN总线通信详解

    CAN总线通信详解
    发表于 03-30 16:46 0次下载

    OpenHarmony总线设计理念

    分布式软总线旨在为OpenHarmony系统提供跨进程或跨设备的通信能力,主要包含软总线和进程间通信两部分。
    的头像 发表于 06-24 10:56 2687次阅读