电子设备知识网-中国电子设备,国内最专业电子设备平台
电子设备知识网-中国电子设备,国内最专业电子设备平台

一文详解OpenHarmony软总线

本次说明可能侧重在标准系统之上。软总线依旧采用鸿蒙经典的 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技术社区】欢迎添加关注!文章转载请注明出处。

审核编辑:汤梓红

未经允许不得转载:电子设备知识网 » 一文详解OpenHarmony软总线

分享到: 生成海报