0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一文詳解OpenHarmony軟總線

OpenHarmony技術(shù)社區(qū) ? 來(lái)源:HarmonyOS技術(shù)社區(qū) ? 作者:HarmonyOS技術(shù)社區(qū) ? 2022-03-30 08:38 ? 次閱讀

本次說(shuō)明可能側(cè)重在標(biāo)準(zhǔn)系統(tǒng)之上。軟總線依舊采用鴻蒙經(jīng)典的 proxy - stub 架構(gòu),接口類 ISoftBusServer,ISoftBusClient。

一般來(lái)說(shuō),一些服務(wù)就一個(gè)接口類,為什么軟總線會(huì)有兩個(gè)呢?我們?cè)倏纯蠢^承關(guān)系。

和 ISoftBusServer 相關(guān)的有:

一文詳解OpenHarmony軟總線

類似的 ISoftBusClient:

一文詳解OpenHarmony軟總線

從上面的圖中可以看出,一個(gè) stub 甚至對(duì)應(yīng)幾個(gè) proxy,看下代碼,可以看到就是 proxy 就是解耦,更加的職責(zé)清晰。

我們通過(guò)觀察目錄結(jié)構(gòu)和對(duì)應(yīng)的代碼接口進(jìn)行查看,便不難看出一二。

先看 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 中的對(duì)外接口。

再看 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");
};

包括發(fā)現(xiàn)設(shè)備,發(fā)布服務(wù),相當(dāng)于這是系統(tǒng)自啟動(dòng)的一個(gè)服務(wù)。

解析一次調(diào)用鏈

對(duì)于 proxy - client 架構(gòu),一般來(lái)說(shuō)就是 client 調(diào)用 sendRequest,server 便會(huì)調(diào)用 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 做分發(fā)。但是對(duì)外的接口都是 c 接口,c++ 接口中沒有任何內(nèi)容存儲(chǔ)信息這是為啥?這是為了兼容標(biāo)準(zhǔn)系統(tǒng)和其他系統(tǒng)。

信息存儲(chǔ)再統(tǒng)一的結(jié)構(gòu)里面,然后根據(jù)不同的系統(tǒng)編譯不同的 .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);
}

實(shí)際調(diào)用的是 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;
}

先做了一些初始化的操作,查找當(dāng)前節(jié)點(diǎn)是否存在。然后 ServerIpcJoinLNN 通信就是使用的 proxy-stub 側(cè)的代碼。

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;
}

這里的關(guān)鍵就是 g_serverProxy->JoinLNN(pkgName,addr,addrTypeLen);

實(shí)際調(diào)用的是:
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;
}

再看對(duì)應(yīng) sub 中 SERVER_JOIN_LNN 值去調(diào)用下面這個(gè)方法:

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;
}

可以看到顯示讀數(shù)據(jù),然后調(diào)用 JoinLNN,你發(fā)現(xiàn) stub 這個(gè)方法為空,但是要注意到這個(gè)方法是一個(gè)虛函數(shù)。

去查看它的子類 SoftBusServer:

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

所以真正調(diào)用的是 LnnIpcServerJoin,我們看下他到底做了什么,這是真正的業(yè)務(wù)邏輯所在。

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;
}

看一下,主要是有幾個(gè)部分,第一查看參數(shù)有效性,第二是不是重復(fù)節(jié)點(diǎn),使用連接地址創(chuàng)建連接,使用包名和地址建立映射。具體的感興趣的小伙伴可以去查看一下。

原文標(biāo)題:OpenHarmony軟總線架構(gòu)分析

文章出處:【微信公眾號(hào):HarmonyOS技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8257

    瀏覽量

    149957
  • 架構(gòu)
    +關(guān)注

    關(guān)注

    1

    文章

    501

    瀏覽量

    25375
  • OpenHarmony
    +關(guān)注

    關(guān)注

    25

    文章

    3548

    瀏覽量

    15740

原文標(biāo)題:OpenHarmony軟總線架構(gòu)分析

文章出處:【微信號(hào):gh_834c4b3d87fe,微信公眾號(hào):OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    OpenHarmony分布式總線流程分析

    OpenHarmony分布式總線流程分析,大神總結(jié),大家可以下載去學(xué)習(xí)了~.~
    發(fā)表于 11-19 15:56

    OpenHarmony總線】——總線啟動(dòng)流程預(yù)覽

    、TransServerInit 傳輸3、AuthInit 認(rèn)證4、DiscServerInit 發(fā)現(xiàn),包含了Coap的初始化,具體怎么實(shí)現(xiàn)組網(wǎng)的還需要研究下5、BusCenterServerInit 總線組網(wǎng)&網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)
    發(fā)表于 01-10 15:37

    OpenHarmony總線】——告別代碼,讓Openharmony總線測(cè)試用例跑起來(lái)!

    目的:openharmony 總線代碼過(guò)于龐大,而且其中有很多地方的功能并沒完善,走讀代碼應(yīng)該是種比較痛苦的方法。此次介紹如何使用
    發(fā)表于 01-10 15:40

    OpenHarmony總線】——連接模塊分析

    設(shè)備通過(guò)公共通信干線來(lái)進(jìn)行通信,設(shè)備需要具備收發(fā)數(shù)據(jù)功能。openharmony 總線需要將不同設(shè)備整合到起,由于不同的設(shè)備通信存在差異,如wifi與藍(lán)牙之間通信存在差異,
    發(fā)表于 01-11 16:16

    OpenHarmony總線】——總線啟動(dòng)流程預(yù)覽

    、TransServerInit 傳輸3、AuthInit 認(rèn)證4、DiscServerInit 發(fā)現(xiàn),包含了Coap的初始化,具體怎么實(shí)現(xiàn)組網(wǎng)的還需要研究下5、BusCenterServerInit 總線組網(wǎng)&網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)
    發(fā)表于 01-26 11:53

    OpenHarmony總線】——告別代碼,讓Openharmony總線測(cè)試用例跑起來(lái)!

    目的:openharmony 總線代碼過(guò)于龐大,而且其中有很多地方的功能并沒完善,走讀代碼應(yīng)該是種比較痛苦的方法。此次介紹如何使用
    發(fā)表于 01-26 11:53

    OpenHarmony總線】——連接模塊分析

    設(shè)備通過(guò)公共通信干線來(lái)進(jìn)行通信,設(shè)備需要具備收發(fā)數(shù)據(jù)功能。openharmony 總線需要將不同設(shè)備整合到起,由于不同的設(shè)備通信存在差異,如wifi與藍(lán)牙之間通信存在差異,
    發(fā)表于 01-26 11:53

    OpenHarmony總線設(shè)計(jì)理念

    分布式總線旨在為OpenHarmony系統(tǒng)提供跨進(jìn)程或跨設(shè)備的通信能力,主要包含總線和進(jìn)程間通信兩部分。
    的頭像 發(fā)表于 06-24 10:56 ?2911次閱讀

    OpenHarmony Tech Day技術(shù)日 通動(dòng)力基于OpenHarmony演講

    通動(dòng)力華南區(qū)大區(qū)總經(jīng)理劉靜就通動(dòng)力基于OpenHarmony的產(chǎn)教融合解決方案進(jìn)行演講
    的頭像 發(fā)表于 04-25 14:19 ?735次閱讀
    <b class='flag-5'>OpenHarmony</b> Tech Day技術(shù)日 <b class='flag-5'>軟</b>通動(dòng)力基于<b class='flag-5'>OpenHarmony</b>演講

    嘗試輕量系統(tǒng)上的總線應(yīng)用

    OpenHarmony”)版本的輕量系統(tǒng)總線能力,將智能燃?xì)鈾z測(cè)設(shè)備和智能窗戶通風(fēng)設(shè)備組成個(gè)輕量級(jí)分布式網(wǎng)絡(luò),實(shí)現(xiàn)設(shè)備之間的相互控制。 原理圖如下: ? 以下是實(shí)際操作效果: 當(dāng)
    的頭像 發(fā)表于 07-08 09:54 ?1080次閱讀

    詳解精密封裝技術(shù)

    詳解精密封裝技術(shù)
    的頭像 發(fā)表于 12-30 15:41 ?1524次閱讀

    詳解分立元件門電路

    詳解分立元件門電路
    的頭像 發(fā)表于 03-27 17:44 ?2482次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>詳解</b>分立元件門電路

    詳解pcb和smt的區(qū)別

    詳解pcb和smt的區(qū)別
    的頭像 發(fā)表于 10-08 09:31 ?2932次閱讀

    詳解pcb地孔的作用

    詳解pcb地孔的作用
    的頭像 發(fā)表于 10-30 16:02 ?1328次閱讀

    詳解pcb的msl等級(jí)

    詳解pcb的msl等級(jí)
    的頭像 發(fā)表于 12-13 16:52 ?7600次閱讀