本次說明可能側重在標準系統之上。軟總線依舊采用鴻蒙經典的 proxy - stub 架構,接口類 ISoftBusServer,ISoftBusClient。
一般來說,一些服務就一個接口類,為什么軟總線會有兩個呢?我們再看看繼承關系。
和 ISoftBusServer 相關的有:
類似的 ISoftBusClient:
從上面的圖中可以看出,一個 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文章
8691瀏覽量
151699 -
架構
+關注
關注
1文章
519瀏覽量
25514 -
OpenHarmony
+關注
關注
25文章
3744瀏覽量
16488
原文標題:OpenHarmony軟總線架構分析
文章出處:【微信號:gh_834c4b3d87fe,微信公眾號:OpenHarmony技術社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論