> 文档中心 > 软总线源码分析2: 接口解析之注册服务和发布服务

软总线源码分析2: 接口解析之注册服务和发布服务

软总线系统本身也是基于IPC对外提供服务,即软总线运行在系统进程中,对外提供一个名为SoftBusServer的服务。

但是软总线与IPC系统存在一些区别,即软总线为双向通信系统,所以客户端进程同时会维护一个本地的名为SoftBusClient的服务。即客户端维护SoftBusServerProxy和SoftBusClientStub,软总线维护SoftBusServerStub和SoftBusClientProxy。

接口1—注册服务:SoftbusRegisterService

当客户端进程想要将自己注册到软总线时,便调用ServerIpcRegisterService函数,齐源码如下所示:

static int ServerIpcRegisterService(const char *name, const void *info){    if (g_serverProxy == nullptr) { LOG_ERR("softbus server g_serverProxy is nullptr!\n"); return SOFTBUS_ERR;    }    int ret = g_serverProxy->SoftbusRegisterService(name, nullptr);    if (ret != SOFTBUS_OK) { LOG_ERR("ServerIpcRegisterService failed!\n"); return ret;    }    LOG_INFO("softbus server register service success!\n");    return SOFTBUS_OK;}

客户端进程使用g_serverProxy保存SoftBusServer的代理对象,其SoftbusRegisterService的函数源码如下:

int32_t SoftBusServerProxy::SoftbusRegisterService(const char *clientPkgName, const sptr& object){    sptr remote = Remote();    if (remote == nullptr) { LOG_ERR("remote is nullptr!"); return SOFTBUS_ERR;    }    MessageParcel data;    int ret = data.WriteRemoteObject(SoftBusServerProxy::GetRemoteInstance());    if (!ret) { LOG_ERR("SoftbusRegisterService write remote object failed!"); return SOFTBUS_ERR;    }    ret = data.WriteCString(clientPkgName);    if (!ret) { LOG_ERR("SoftbusRegisterService write clientPkgName failed!"); return SOFTBUS_ERR;    }    MessageParcel reply;    MessageOption option;    int32_t err = remote->SendRequest(MANAGE_REGISTER_SERVICE, data, reply, option);    if (err != 0) { LOG_ERR("SoftbusRegisterService send request failed!"); return SOFTBUS_ERR;    }    int32_t serverRet = 0;    ret = reply.ReadInt32(serverRet);    if (!ret) { LOG_ERR("SoftbusRegisterService read serverRet failed!"); return SOFTBUS_ERR;    }    return SOFTBUS_OK;}

由上述源码可知,客户端进程将自己的应用包名,和调用GetRemoteInstance()后获取的SoftBusClientProxy对象,一起发送给服务端进程。服务端对应的SoftbusRegisterService源码如下:

int32_t SoftBusServer::SoftbusRegisterService(const char *clientPkgName, const sptr &object){    if (object == nullptr) { LOG_ERR("RegisterService object is nullptr\n"); return SOFTBUS_ERR;    }    std::lock_guard autoLock(clientObjectMapLock_);    clientObjectMap_.insert(std::pair<std::string, sptr>(clientPkgName, object));    abilityDeath_ = sptr(new (std::nothrow) SoftBusDeathRecipient());    if (abilityDeath_ == nullptr) { LOG_ERR("DeathRecipient object is nullptr\n"); return SOFTBUS_ERR;    }    bool ret = object->AddDeathRecipient(abilityDeath_);    if (!ret) { LOG_ERR("AddDeathRecipient failed\n"); return SOFTBUS_ERR;    }    return SOFTBUS_OK;}

服务端的处理很简单,就是应用包名和对应客户端进程的SoftBusClientStub对象,保存在一个名为clientObjectMap_的键值库中。

接口2—发布服务:PublishService

该接口为客户端进程发布指定的服务。与发布该服务的设备在同一局域网内的对等设备可以根据需要发现该服务,服务通过publicIdpkgName进行标识。其函数为ServerIpcPublishService,对应的源码如下:

static int ServerIpcPublishService(const char *pkgName, const void *info){    if (g_serverProxy == nullptr) { LOG_ERR("softbus server g_serverProxy is nullptr!\n"); return SOFTBUS_ERR;    }    int ret = g_serverProxy->PublishService(pkgName, info);    return ret;}

即调用客户端的代理对象的方法PublishService,其函数源码为:

int32_t SoftBusServerProxy::PublishService(const char *pkgName, const void *info){    sptr remote = Remote();    if (remote == nullptr) { LOG_ERR("remote is nullptr!"); return SOFTBUS_ERR;    }    MessageParcel data;    PublishInfo *pubInfo = (PublishInfo *)info;    data.WriteCString(pkgName);    data.WriteInt32(pubInfo->publishId);    data.WriteInt32(pubInfo->mode);    data.WriteInt32(pubInfo->medium);    data.WriteInt32(pubInfo->freq);    data.WriteCString(pubInfo->capability);    data.WriteCString((char *)pubInfo->capabilityData);    data.WriteUint32(pubInfo->dataLen);    MessageParcel reply;    MessageOption option;    int32_t err = remote->SendRequest(SERVER_PUBLISH_SERVICE, data, reply, option);    LOG_ERR("PublishService send request ret = %d!", err);    if (err != 0) { LOG_ERR("PublishService send request failed!"); return SOFTBUS_ERR;    }    int32_t serverRet = 0;    int32_t ret = reply.ReadInt32(serverRet);    if (!ret) { LOG_ERR("PublishService read serverRet failed!"); return SOFTBUS_ERR;    }    return serverRet;}

由代码可知,客户端将包名和服务相关的信息一起发送到客户端,服务信息保存在PublishInfo结构体中,其主要成员变量包括publishId,mode(主动发现/被动发现),medium(蓝牙/USB/COAP),freq(慢速/中速/快速/超高速),capability(HiCall/HomeVisionPic)等。

服务端手段对应的消息后,调用PublishServiceInner处理该请求,源码如下:

int32_t SoftBusServerStub::PublishServiceInner(MessageParcel &data, MessageParcel &reply){    PublishInfo pubInfo;    const char *pkgName = data.ReadCString();    pubInfo.publishId = data.ReadInt32();    pubInfo.mode = (DiscoverMode)data.ReadInt32();    pubInfo.medium = (ExchanageMedium)data.ReadInt32();    pubInfo.freq = (ExchangeFreq)data.ReadInt32();    pubInfo.capability = data.ReadCString();    pubInfo.capabilityData = (unsigned char *)data.ReadCString();    pubInfo.dataLen = data.ReadUint32();    int32_t retReply = PublishService(pkgName, &pubInfo);    if (!reply.WriteInt32(retReply)) { LOG_ERR("PublishServiceInner write reply failed!"); return SOFTBUS_ERR;    }    return SOFTBUS_OK;}

PublishServiceInner获取消息中的对象后,调用PublishService,PublishService又调用DiscIpcPublishService,DiscIpcPublishService进行权限检查后,又调用DiscPublishService,其源码为:

int32_t DiscPublishService(const char *packageName, const PublishInfo *info, const IServerPublishCallback *cb){    int32_t ret;    if ((packageName == NULL) || (info == NULL) || (cb == NULL)) { return SOFTBUS_INVALID_PARAM;    }    ret = PublishInfoCheck(packageName, info);    if (ret != SOFTBUS_OK) { goto EXIT;    }    if (g_isInited == false) { LOG_ERR("not init"); ret = SOFTBUS_DISCOVER_MANAGER_NOT_INIT; goto EXIT;    }    DiscInfo *infoNode = CreateNewPublishInfoNode(info);    if (infoNode == NULL) { LOG_ERR("infoNode create failed"); ret = SOFTBUS_DISCOVER_MANAGER_INFO_NOT_CREATE; goto EXIT;    }    ret = InnerPublishService(packageName, infoNode, cb, PUBLISH_SERVICE);    if (ret != SOFTBUS_OK) { ReleaseInfoNodeMem(infoNode, PUBLISH_SERVICE); goto EXIT;    }    cb->OnServerPublishSuccess(packageName, info->publishId);    return SOFTBUS_OK;EXIT:    if (ret == SOFTBUS_DISCOVER_MANAGER_INVALID_MEDIUM) { cb->OnServerPublishFail(packageName, info->publishId, PUBLISH_FAIL_REASON_NOT_SUPPORT_MEDIUM); return ret;    }    cb->OnServerPublishFail(packageName, info->publishId, PUBLISH_FAIL_REASON_INTERNAL);    return ret;}

总共分为三部分:1.创建一个内部的服务信息InfoNode,2.调用InnerPublishService,3.发布成功,调用回调函数OnServerPublishSuccess。

InnerPublishService的源码如下:

static int32_t InnerPublishService(const char *packageName, DiscInfo *info, const IServerPublishCallback *cb,    const ServiceType type){    int32_t ret;    InnerCallback callback;    if ((cb != NULL) && (memcpy_s(&(callback.publishCb), PUBLISH_CB_LEN, cb, PUBLISH_CB_LEN) != EOK)) { LOG_ERR("memcpy_s erro"); return SOFTBUS_MEM_ERR;    }    ret = AddInfoToList(g_publishInfoList, packageName, &callback, info, type);    if (ret != SOFTBUS_OK) { LOG_ERR("add list fail"); return ret;    }    ret = DiscInterfaceByMedium(info, PUBLISH_FUNC);    if (ret != SOFTBUS_OK) { LOG_ERR("interface fail"); return ret;    }    return SOFTBUS_OK;}

即将InfoNode加到系统内部维护的全局列表g_publishInfoList中,随后调用DiscInterfaceByMedium,该函数即根据InfoNode的类型(例如蓝牙或者COAP),调用对应的Publish处理。

回调函数OnServerPublishSuccess最终会调用ClientIpcOnPublishSuccess,其源码如下:

static int ClientIpcOnPublishSuccess(const char *pkgName, int publishId){    sptr clientProxy = GetClientProxy(pkgName);    if (clientProxy == nullptr) { LOG_ERR("softbus client proxy is nullptr!\n"); return SOFTBUS_ERR;    }    clientProxy->OnPublishSuccess(publishId);    return SOFTBUS_OK;}

ClientIpcOnPublishSucces获取SoftBusClient的代理对象后,调用其OnPublishSuccess方法。获取SoftBusClient代理的方法源码如下:

static sptr GetClientProxy(const char *pkgName){    sptr softbusServer = SoftBusServer::GetInstance();    if (softbusServer == nullptr) { LOG_ERR("softbusServer is nullptr!\n"); return nullptr;    }    sptr clientProxy = softbusServer->GetSoftbusClientProxy(pkgName);    return clientProxy;}

其调用了SoftBusServer的函数GetSoftbusClientProxy,其源码如下:

sptr SoftBusServer::GetSoftbusClientProxy(const char *pkgName){    std::lock_guard autoLock(clientObjectMapLock_);    auto iter = clientObjectMap_.find(pkgName);    if (iter != clientObjectMap_.end()) { sptr clientProxy = iface_cast(iter->second); if (clientProxy != nullptr) {     return clientProxy; }    }    LOG_ERR("GetSoftbusClientProxy client proxy is nullptr\n");    return nullptr;}

clientObjectMap_即为调用接口1:SoftbusRegisterService时,保存在服务端本地的SoftbusClientProxy对象。所以客户端应用在调用Publish发布服务时,应首先向服务端注册自己的应用包。SoftbusClientProxy的OnPublishSuccess方法源码如下:

void SoftBusClientProxy::OnPublishSuccess(int publishId){    sptr remote = Remote();    if (remote == nullptr) { LOG_ERR("remote is nullptr"); return;    }    MessageParcel data;    data.WriteInt32(publishId);    MessageParcel reply;    MessageOption option;    int32_t err = remote->SendRequest(CLIENT_PUBLISH_SUCC, data, reply, option);    if (err != 0) { LOG_ERR("OnPublishSuccess send request failed"); return;    }}

即将发布成功的服务对应的PubId写回到客户端应用,客户端与之对应的对象SoftbusClientStub调用方法OnPublishFailInner,起源码如下

int32_t SoftBusClientStub::OnPublishSuccessInner(MessageParcel &data, MessageParcel &reply){    int publishId = data.ReadInt32();    OnPublishSuccess(publishId);    return SOFTBUS_OK;}

最终OnPublishSuccess又会调用DiscClientOnPublishSuccess,其源码如下

void DiscClientOnPublishSuccess(int32_t publishId){    g_discInfo->publishCb.OnPublishSuccess(publishId);}

g_discInfo中的回调为调用AddPublishInfo时增加的回调函数。

至此,接口2:PublishService也已分析完毕