源码分析- openHarmony软总线 原创 精华

拓维信息流沙客
发布于 2022-3-16 15:44
浏览
9收藏

openHarmony软总线架构分析

基本类阐述

本次说明可能侧重在标准系统之上。

软总线依旧采用鸿蒙经典的proxy - stub 架构,接口类 ISoftBusServer,ISoftBusClient。一般来说,一些服务就一个接口类,为什么软总线会有两个呢?,我们再看看继承关系。
proxy -stub 可以参考 https://ost.51cto.com/posts/10765

和ISoftBusServer 相关的有
源码分析- openHarmony软总线-鸿蒙开发者社区

类似的 ISoftBusClient
源码分析- openHarmony软总线-鸿蒙开发者社区

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

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

先看 ISoftBusClient 接口类

namespace OHOS {
class ISoftBusClient : public IRemoteBroker {
public:
    virtual ~ISoftBusClient() = default;

    virtual void OnDeviceFound(const DeviceInfo *device) = 0;
    virtual void OnDiscoverFailed(int subscribeId, int failReason) = 0;
    virtual void OnDiscoverySuccess(int subscribeId) = 0;
    virtual void OnPublishSuccess(int publishId) = 0;
    virtual void OnPublishFail(int publishId, int reason) = 0;
    virtual int32_t OnChannelOpened(const char *sessionName, const ChannelInfo *channel) = 0;
    virtual int32_t OnChannelOpenFailed(int32_t channelId, int32_t channelType) = 0;
    virtual int32_t OnChannelLinkDown(const char *networkId, int32_t routeType) = 0;
    virtual int32_t OnChannelMsgReceived(int32_t channelId, int32_t channelType, const void *data,
        uint32_t len, int32_t type) = 0;
    virtual int32_t OnChannelClosed(int32_t channelId, int32_t channelType) = 0;
    virtual int32_t OnChannelQosEvent(int32_t channelId, int32_t channelType, int32_t eventId, int32_t tvCount,
        const QosTv *tvList) = 0;
    virtual int32_t OnJoinLNNResult(void *addr, uint32_t addrTypeLen, const char *networkId, int retCode) = 0;
    virtual int32_t OnLeaveLNNResult(const char *networkId, int retCode) = 0;
    virtual int32_t OnNodeOnlineStateChanged(bool isOnline, void *info, uint32_t infoTypeLen) = 0;
    virtual int32_t OnNodeBasicInfoChanged(void *info, uint32_t infoTypeLen, int32_t type) = 0;
    virtual int32_t OnTimeSyncResult(const void *info, uint32_t infoTypeLen, int32_t retCode) = 0;
    virtual void OnPublishLNNResult(int32_t publishId, int32_t reason);
    virtual void OnRefreshLNNResult(int32_t refreshId, int32_t reason);
    virtual void OnRefreshDeviceFound(const void *device, uint32_t deviceLen);

public:
    DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.ISoftBusClient");
};
} // namespace OHOS

其中的接口方法就是主要的SDK中的对外接口。

再看ISoftBusServer

namespace OHOS {
class ISoftBusServer : public IRemoteBroker {
public:
    virtual ~ISoftBusServer() = default;

    virtual int32_t StartDiscovery(const char *pkgName, const SubscribeInfo *info) = 0;
    virtual int32_t StopDiscovery(const char *pkgName, int subscribeId) = 0;
    virtual int32_t PublishService(const char *pkgName, const PublishInfo *info) = 0;
    virtual int32_t UnPublishService(const char *pkgName, int publishId) = 0;
    virtual int32_t SoftbusRegisterService(const char *clientPkgName, const sptr<IRemoteObject> &object) = 0;

    virtual int32_t CreateSessionServer(const char *pkgName, const char *sessionName) = 0;
    virtual int32_t RemoveSessionServer(const char *pkgName, const char *sessionName) = 0;
    virtual int32_t OpenSession(const SessionParam *param, TransInfo *info) = 0;
    virtual int32_t OpenAuthSession(const char *sessionName, const ConnectionAddr *addrInfo) = 0;
    virtual int32_t NotifyAuthSuccess(int channelId) = 0;
    virtual int32_t CloseChannel(int32_t channelId, int32_t channelType) = 0;
    virtual int32_t SendMessage(int32_t channelId, int32_t channelType,
        const void *data, uint32_t len, int32_t msgType) = 0;
    virtual int32_t JoinLNN(const char *pkgName, void *addr, uint32_t addrTypeLen) = 0;
    virtual int32_t LeaveLNN(const char *pkgName, const char *networkId) = 0;
    virtual int32_t GetAllOnlineNodeInfo(const char *pkgName, void **info, uint32_t infoTypeLen, int *infoNum) = 0;
    virtual int32_t GetLocalDeviceInfo(const char *pkgName, void *info, uint32_t infoTypeLen) = 0;
    virtual int32_t GetNodeKeyInfo(const char *pkgName, const char *networkId, int key, unsigned char *buf,
        uint32_t len) = 0;
    virtual int32_t StartTimeSync(const char *pkgName, const char *targetNetworkId, int32_t accuracy,
        int32_t period) = 0;
    virtual int32_t StopTimeSync(const char *pkgName, const char *targetNetworkId) = 0;
    virtual int32_t QosReport(int32_t channelId, int32_t chanType, int32_t appType, int32_t quality) = 0;
    virtual int32_t PublishLNN(const char *pkgName, const void *info, uint32_t infoTypeLen);
    virtual int32_t StopPublishLNN(const char *pkgName, int32_t publishId);
    virtual int32_t RefreshLNN(const char *pkgName, const void *info, uint32_t infoTypeLen);
    virtual int32_t StopRefreshLNN(const char *pkgName, int32_t refreshId);
    virtual int32_t ActiveMetaNode(const MetaNodeConfigInfo *info, char *metaNodeId);
    virtual int32_t DeactiveMetaNode(const char *metaNodeId);
    virtual int32_t GetAllMetaNodeInfo(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_t JoinLNN(const char *pkgName, ConnectionAddr *target, OnJoinLNNResult cb)
{
    if (pkgName == NULL || target == NULL || cb == NULL) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "fail : params are NULL!");
        return SOFTBUS_INVALID_PARAM;
    }
    if (CommonInit(pkgName) != SOFTBUS_OK) {
        return SOFTBUS_INVALID_PARAM;
    }
    return JoinLNNInner(pkgName, target, cb);
}

实际调用的是joinLNNInner

int32_t JoinLNNInner(const char *pkgName, ConnectionAddr *target, OnJoinLNNResult cb)
{
    int32_t rc;

    if (!g_busCenterClient.isInit) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "fail : join lnn not init");
        return SOFTBUS_NO_INIT;
    }
    if (SoftBusMutexLock(&g_busCenterClient.lock) != 0) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "fail: lock join lnn cb list in join");
    }
    rc = SOFTBUS_ERR;
    do {
        if (FindJoinLNNCbItem(target, cb) != NULL) {
            SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "fail : join request already exist");
            rc = SOFTBUS_ALREADY_EXISTED;
            break;
        }
        rc = ServerIpcJoinLNN(pkgName, target, sizeof(*target));
        if (rc != SOFTBUS_OK) {
            SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "fail : request join lnn");
        } else {
            rc = AddJoinLNNCbItem(target, cb);
        }
    } while (false);
    if (SoftBusMutexUnlock(&g_busCenterClient.lock) != 0) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "fail: unlock join lnn cb list in join");
    }
    return rc;
}

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

int32_t ServerIpcJoinLNN(const char *pkgName, void *addr, unsigned int addrTypeLen)
{
    if (g_serverProxy == nullptr) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "ServerIpcJoinLNN g_serverProxy is nullptr!\n");
        return SOFTBUS_ERR;
    }
    int ret = g_serverProxy->JoinLNN(pkgName, addr, addrTypeLen);
    if (ret != 0) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "ServerIpcJoinLNN failed!\n");
        return ret;
    }
    return SOFTBUS_OK;
}

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

实际调用的是

int32_t BusCenterServerProxy::JoinLNN(const char *pkgName, void *addr, uint32_t addrTypeLen)
{
    if (pkgName == nullptr || addr == nullptr) {
        return SOFTBUS_ERR;
    }
    sptr<IRemoteObject> remote = GetSystemAbility();
    if (remote == nullptr) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "remote is nullptr!");
        return SOFTBUS_ERR;
    }

    MessageParcel data;
    if (!data.WriteCString(pkgName)) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "JoinLNN write client name failed!");
        return SOFTBUS_ERR;
    }
    if (!data.WriteUint32(addrTypeLen)) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "JoinLNN write addr type length failed!");
        return SOFTBUS_ERR;
    }
    if (!data.WriteRawData(addr, addrTypeLen)) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "JoinLNN write addr failed!");
        return SOFTBUS_ERR;
    }
    MessageParcel reply;
    MessageOption option;
    if (remote->SendRequest(SERVER_JOIN_LNN, data, reply, option) != 0) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "JoinLNN send request failed!");
        return SOFTBUS_ERR;
    }
    int32_t serverRet = 0;
    if (!reply.ReadInt32(serverRet)) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "JoinLNN read serverRet failed!");
        return SOFTBUS_ERR;
    }
    return serverRet;
}

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

int32_t SoftBusServerStub::JoinLNNInner(MessageParcel &data, MessageParcel &reply)
{
    const char *clientName = data.ReadCString();
    if (clientName == nullptr) {
        SoftBusLog(SOFTBUS_LOG_COMM, SOFTBUS_LOG_ERROR, "SoftbusJoinLNNInner read clientName failed!");
        return SOFTBUS_ERR;
    }
    uint32_t addrTypeLen;
    if (!data.ReadUint32(addrTypeLen)) {
        SoftBusLog(SOFTBUS_LOG_COMM, SOFTBUS_LOG_ERROR, "SoftbusJoinLNNInner read addr type length failed!");
        return SOFTBUS_ERR;
    }
    void *addr = (void *)data.ReadRawData(addrTypeLen);
    if (addr == nullptr) {
        SoftBusLog(SOFTBUS_LOG_COMM, SOFTBUS_LOG_ERROR, "SoftbusJoinLNNInner read addr failed!");
        return SOFTBUS_ERR;
    }
    int32_t retReply = JoinLNN(clientName, addr, addrTypeLen);
    if (!reply.WriteInt32(retReply)) {
        SoftBusLog(SOFTBUS_LOG_COMM, SOFTBUS_LOG_ERROR, "SoftbusJoinLNNInner write reply failed!");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

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

去查看它的子类SoftBusServer。

int32_t SoftBusServer::JoinLNN(const char *pkgName, void *addr, uint32_t addrTypeLen)
{
    return LnnIpcServerJoin(pkgName, addr, addrTypeLen);
}

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

int32_t LnnIpcServerJoin(const char *pkgName, void *addr, uint32_t addrTypeLen)
{
    ConnectionAddr *connAddr = (ConnectionAddr *)addr;

    (void)addrTypeLen;
    if (pkgName == nullptr || connAddr == nullptr) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "parameters are nullptr!\n");
        return SOFTBUS_INVALID_PARAM;
    }
    std::lock_guard<std::mutex> autoLock(g_lock);
    if (IsRepeatJoinLNNRequest(pkgName, connAddr)) {
        SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "repeat join lnn request from: %s", pkgName);
        return SOFTBUS_ALREADY_EXISTED;
    }
    int32_t ret = LnnServerJoin(connAddr);
    if (ret == SOFTBUS_OK) {
        ret = AddJoinLNNInfo(pkgName, connAddr);
    }
    return ret;
}

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

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-3-17 11:25:41修改
11
收藏 9
回复
举报
8条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

大佬,好像前两张图挂了

1
回复
2022-3-16 17:24:12
拓维信息流沙客
拓维信息流沙客 回复了 红叶亦知秋
大佬,好像前两张图挂了

我自己这边显示正常的

1
回复
2022-3-16 17:31:57
红叶亦知秋
红叶亦知秋

会不会是图片取到本地了,能麻烦大佬在上传下吗

1
回复
2022-3-16 17:37:07
拓维信息流沙客
拓维信息流沙客

 

 

2
回复
2022-3-16 17:53:18
民之码农
民之码农

666

2
回复
2022-3-17 14:57:37
科技维度
科技维度

优质内容,顶顶顶

 

 

3
回复
2022-3-18 09:11:31
拓维信息Abin
拓维信息Abin

66666

1
回复
2022-3-25 14:28:32
fangye945a
fangye945a

666666666666 

回复
2022-8-5 17:09:19
回复
    相关推荐