(发现服务)

前言

经过本人分析,我下载的5.1版本的项目代码,项目自带的readme文件和项目解读文档有不少错的,搞得我都乱了,所以我决定再依赖资料分析,直接啃代码,前面分析到发布服务了,接下来到了发现服务。

先字面分析一下发现服务的含义。设备注册挂载到分布式软总线了以后,需要把自己的能提供的能力发布出来共其他设备访问使用,就我目前了解到的,在/foundation/communication/dsoftbus/core/discovery/manager/这个文件夹根据他的名字来看就是发现服务的核心代码,有两个文件,一个叫disc_manager,一个叫softbus_disc_server。前者是发现管理核心业务代码,仅通过 disc_manager.h 暴露接口,后者是服务端框架适配层,被 SoftBus 框架层直接调用,开始通过源码反推发现服务业务流程。

入口

初始化

在框架层会提供服务和模块初始化函数(/foundation/communication/dsoftbus/core/frame/common/src/softbus_server_frame.c)

函数

static int32_t InitServicesAndModules(void)

涉及实现

 if (DiscServerInit() != SOFTBUS_OK) {
        COMM_LOGE(COMM_SVC, "softbus disc server init failed.");
        return SOFTBUS_DISC_SERVER_INIT_FAILED;
    }

这个DiscServerInit是框架层对系统暴露的接口,实际是封装的

int32_t DiscMgrInit(void)
{
    DISC_CHECK_AND_RETURN_RET_LOGE(g_isInited == false, SOFTBUS_OK, DISC_INIT, "already inited");

    g_discMgrMediumCb.OnDeviceFound = DiscOnDeviceFound;

    g_discCoapInterface = DiscCoapInit(&g_discMgrMediumCb);
    g_discBleInterface = DiscBleInit(&g_discMgrMediumCb);
    g_discUsbInterface = DiscUsbDispatcherInit(&g_discMgrMediumCb);

    DISC_CHECK_AND_RETURN_RET_LOGE(g_discBleInterface != NULL || g_discCoapInterface != NULL ||
        g_discUsbInterface != NULL, SOFTBUS_DISCOVER_MANAGER_INIT_FAIL, DISC_INIT, "ble coap and usb init failed");

    g_publishInfoList = CreateSoftBusList();
    DISC_CHECK_AND_RETURN_RET_LOGE(g_publishInfoList != NULL, SOFTBUS_DISCOVER_MANAGER_INIT_FAIL, DISC_INIT,
        "init publish info list failed");
    g_discoveryInfoList = CreateSoftBusList();
    if (g_discoveryInfoList == NULL) {
        DISC_LOGE(DISC_INIT, "init discovery Info List failed");
        DestroySoftBusList(g_publishInfoList);
        g_publishInfoList = NULL;
        return SOFTBUS_DISCOVER_MANAGER_INIT_FAIL;
    }

    for (int32_t i = 0; i < CAPABILITY_MAX_BITNUM; i++) {
        ListInit(&g_capabilityList[i]);
    }

    g_isInited = true;
    return SOFTBUS_OK;
}

将DiscOnDeviceFound注册到三个介质,使得 BLE/CoAP/USB 任何介质发现设备后,都会回调到 DiscOnDeviceFound → InnerDeviceFound → 通知订阅者。这是整个被动通知机制的注册点。

三种介质至少一个成功即可,允许部分介质不可用(如设备无蓝牙则 BLE 初始化失败,但 CoAP 仍可用)。

g_publishInfoList      ← 发布服务链表
g_discoveryInfoList    ← 发现服务链表
g_capabilityList[0~15] ← 16 个 capability 匹配桶(对应 bitmap 位号 0~15)
static void DiscOnDeviceFound(const DeviceInfo *device, const InnerDeviceInfoAddtions *additions)
{
    // 1. 参数校验
    DISC_CHECK_AND_RETURN_LOGE(device != NULL, ...);
    DISC_CHECK_AND_RETURN_LOGE(additions != NULL, ...);

    // 2. 遍历设备 capabilityBitmap 的每一位 (0~15)
    for (uint32_t tmp = 0; tmp < CAPABILITY_MAX_BITNUM; tmp++) {
        // 3. 该位未置位 → 设备没有这个能力 → 跳过
        if (IsBitmapSet((uint32_t *)device->capabilityBitmap, tmp) == false) {
            continue;
        }

        // 4. 加锁保护 g_capabilityList
        if (SoftBusMutexLock(&(g_discoveryInfoList->lock)) != SOFTBUS_OK) {
            return;
        }

        // 5. 遍历该 capability 对应桶中的所有订阅者
        DiscInfo *infoNode = NULL;
        LIST_FOR_EACH_ENTRY(infoNode, &(g_capabilityList[tmp]), DiscInfo, capNode) {
            infoNode->statistics.discTimes++;           // 统计:该订阅者被匹配到的次数
            InnerDeviceFound(infoNode, device, additions);  // 通知该订阅者
        }

        // 6. 解锁
        (void)SoftBusMutexUnlock(&(g_discoveryInfoList->lock));
    }
}
介质层发现设备 (BLE/CoAP/USB)
  │
  │  回调传入: device->capabilityBitmap[0] = 0x88
  │  含义: bit3(castPlus) + bit7(osdCapability)
  │
  ▼
DiscOnDeviceFound()
  │
  │  tmp=0: IsBitmapSet(0x88, 0) = false → 跳过
  │  tmp=1: IsBitmapSet(0x88, 1) = false → 跳过
  │  tmp=2: IsBitmapSet(0x88, 2) = false → 跳过
  │  tmp=3: IsBitmapSet(0x88, 3) = true  → 遍历 g_capabilityList[3]
  │         ┌──────────────────────────────────────────────┐
  │         │ 订阅了 castPlus 的应用A → InnerDeviceFound() │
  │         │ 订阅了 castPlus 的应用B → InnerDeviceFound() │
  │         └──────────────────────────────────────────────┘
  │  tmp=4~6: false → 跳过
  │  tmp=7: IsBitmapSet(0x88, 7) = true  → 遍历 g_capabilityList[7]
  │         ┌──────────────────────────────────────────────┐
  │         │ 订阅了 osdCapability 的应用C → InnerDeviceFound() │
  │         │ 订阅了 osdCapability 的应用D → InnerDeviceFound() │
  │         └──────────────────────────────────────────────┘
  │  tmp=8~15: false → 跳过
  │
  ▼
完成:所有匹配的订阅者都已被通知

反初始化

SoftBus 服务端关闭时调用,是整个发现模块的逆初始化入口,与 DiscServerInit 配对使用,确保所有资源被完整释放。

DiscServerDeinit()---------》    DiscMgrDeinit();
void DiscMgrDeinit(void)
{
    DISC_CHECK_AND_RETURN_LOGW(g_isInited == true, ...);   // 1. 防重入:未初始化则直接返回

    RemoveAllDiscInfoForPublish();     // 2. 清理所有发布信息
    RemoveAllDiscInfoForDiscovery();   // 3. 清理所有发现信息

    g_discCoapInterface = NULL;        // 4. 置空三个介质接口指针
    g_discBleInterface = NULL;
    g_discUsbInterface = NULL;

    DiscCoapDeinit();                  // 5. 反初始化 CoAP 介质
    DiscBleDeinit();                   // 6. 反初始化 BLE 介质
    DiscUsbDispatcherDeinit();         // 7. 反初始化 USB 介质

    g_isInited = false;                // 8. 标记为未初始化
}
步骤 操作 说明
1 g_isInited 检查 防止重复反初始化
2 RemoveAllDiscInfoForPublish() 清理 g_publishInfoList,停止所有正在发布的服务
3 RemoveAllDiscInfoForDiscovery() 清理 g_discoveryInfoList + g_capabilityList,停止所有正在进行的发现
4 三个接口指针置 NULL 断开与介质实现的引用
5-7 三个介质 Deinit 释放 BLE/CoAP/USB 各自的资源(定时器、广播、监听等)
8 g_isInited = false 标记模块已反初始化

异常回调

客户端进程死亡(崩溃/被杀/异常退出)时,SoftBus 框架层检测到进程死亡,调用此回调。

客户端进程崩溃
  → SoftBus 框架检测到进程死亡
  → DiscServerDeathCallback(pkgName, pid)

   DiscServerDeathCallback----》DiscMgrDeathCallback
void DiscMgrDeathCallback(const char *pkgName, int32_t pid)
{
    DISC_CHECK_AND_RETURN_LOGE(pkgName != NULL, ...);                          // 1. 参数校验
    DISC_CHECK_AND_RETURN_LOGE(!IsInnerPackageName(pkgName), ...);             // 2. 内部包名不处理
    DISC_CHECK_AND_RETURN_LOGE(g_isInited == true, ...);                       // 3. 模块已初始化
    DISC_CHECK_AND_RETURN_LOGE(pid != getpid(), ...);                          // 4. PID 校验

    RemoveDiscInfoForPublish(pkgName, pid);     // 5. 清理该进程的所有发布
    RemoveDiscInfoForDiscovery(pkgName, pid);   // 6. 清理该进程的所有发现
}
校验 原因
pkgName != NULL 防空指针
!IsInnerPackageName(pkgName) 内部模块(如软总线自身)不会死亡,不需要清理
g_isInited == true 模块未初始化时没有资源需要清理
pid != getpid() 死亡的是客户端进程,不是服务端自身

执行流程

DiscServerDeathCallback("com.example.app", 12345)
  │
  ├─ RemoveDiscInfoForPublish(pkgName, pid)
  │   → RemoveDiscInfoByPackageName(g_publishInfoList, PUBLISH_SERVICE, pkgName, pid)
  │       │
  │       │  遍历 g_publishInfoList 中该 pkgName+pid 的所有发布项
  │       │  收集到待清理 ID 列表
  │       │
  │       ▼
  │     CleanupPublishDiscovery(&ids, PUBLISH_SERVICE)
  │       → 逐个调用底层介质的 Unpublish / StopScan 停止发布
  │       → 从链表中删除节点
  │       → 减少引用计数
  │
  └─ RemoveDiscInfoForDiscovery(pkgName, pid)
      → RemoveDiscInfoByPackageName(g_discoveryInfoList, SUBSCRIBE_SERVICE, pkgName, pid)
          │
          │  遍历 g_discoveryInfoList 中该 pkgName+pid 的所有发现项
          │  收集到待清理 ID 列表
          │
          ▼
        CleanupPublishDiscovery(&ids, SUBSCRIBE_SERVICE)
          → 逐个调用底层介质的 StopAdvertise / Unsubscribe 停止发现
          → 从链表和 g_capabilityList 中删除节点
          → 减少引用计数

总结

发布服务生命周期流程

SoftBus 服务端启动
  │
  ▼
DiscServerInit()                          ← softbus_disc_server.c:22
  → DiscMgrInit()                         ← disc_manager.c:1312
      ├─ 注册介质回调: g_discMgrMediumCb.OnDeviceFound = DiscOnDeviceFound
      ├─ 初始化三个介质: DiscCoapInit / DiscBleInit / DiscUsbDispatcherInit
      ├─ 创建管理链表: g_publishInfoList / g_discoveryInfoList
      ├─ 初始化匹配桶: g_capabilityList[0~15]
      └─ g_isInited = true
  │
  │  ════════════ 正常运行阶段 ════════════
  │
  │  发布服务 ←→ 发现服务 ←→ 设备匹配通知
  │
  ▼
DiscServerDeinit()                        ← softbus_disc_server.c:32
  → DiscMgrDeinit()                       ← disc_manager.c:1344
      ├─ RemoveAllDiscInfoForPublish()     清理所有发布
      ├─ RemoveAllDiscInfoForDiscovery()   清理所有发现
      ├─ 三个介质接口置 NULL
      ├─ DiscCoapDeinit / DiscBleDeinit / DiscUsbDispatcherDeinit
      └─ g_isInited = false

异常路径:客户端进程死亡时:

客户端进程崩溃
  │
  ▼
DiscServerDeathCallback(pkgName, pid)     ← softbus_disc_server.c:37
  → DiscMgrDeathCallback()                ← disc_manager.c:1300
      ├─ RemoveDiscInfoForPublish(pkgName, pid)    清理该进程的发布
      └─ RemoveDiscInfoForDiscovery(pkgName, pid)  清理该进程的发现

发现服务主流程

┌─────────────────────────────────────────────────────────────────────┐
│                        1. 启动发现                                   │
│                                                                     │
│  DiscStartDiscovery(pkgName, info, cb, callingPid)   ← L932       │
│    ├─ CheckSubscribeInfo()           参数校验                       │
│    ├─ IsSameSubscribeInfo()          重复订阅检查                    │
│    ├─ CreateDiscInfoForSubscribe()   创建节点                       │
│    │     capability字符串 → capabilityBitmap                        │
│    └─ InnerStartDiscovery()          内部实现          ← L850       │
│          ├─ 提取回调 OnServerDeviceFound / OnDeviceFound           │
│          ├─ 加锁 g_discoveryInfoList                                │
│          ├─ AddDiscInfoToDiscoveryList()   注册到发现链表           │
│          ├─ AddDiscInfoToCapabilityList()  注册到匹配桶             │
│          │     按 bitmap 位号挂到 g_capabilityList[bit]             │
│          ├─ UpdateDdmpStartDiscoveryTime()  更新时间戳              │
│          ├─ CallInterfaceByMedium(STARTDISCOVERTY_FUNC)             │
│          │     ├─ ACTIVE  → interface->StartAdvertise()            │
│          │     └─ PASSIVE → interface->Subscribe()                 │
│          ├─ 失败回滚: 删除节点 + 减引用计数                         │
│          └─ 解锁                                                     │
└─────────────────────────────────────────────────────────────────────┘
                              │
                              │  介质层持续监听/广播
                              ▼
┌─────────────────────────────────────────────────────────────────────┐
│                     2. 设备匹配通知                                  │
│                                                                     │
│  介质层发现设备 → 回调 DiscOnDeviceFound(device)      ← L406       │
│    │                                                                │
│    │  遍历 device->capabilityBitmap 每一位:                         │
│    │    for (tmp = 0; tmp < 16; tmp++)                              │
│    │      if (IsBitmapSet(bitmap, tmp))                             │
│    │                                                                │
│    │  ★ 设备能力 与 订阅者能力 按位匹配                              │
│    │                                                                │
│    ▼                                                                │
│  遍历 g_capabilityList[tmp] 中的订阅者:                             │
│    LIST_FOR_EACH_ENTRY(infoNode, &g_capabilityList[tmp])            │
│      │                                                              │
│      ├─ infoNode->statistics.discTimes++   统计匹配次数             │
│      │                                                              │
│      ▼                                                              │
│  InnerDeviceFound(infoNode, device)                   ← L390       │
│    ├─ 外部模块 → OnServerDeviceFound(pkgName, device)              │
│    └─ 内部模块 → OnDeviceFound(device)                             │
└─────────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────────┐
│                       3. 停止发现                                    │
│                                                                     │
│  DiscStopDiscovery(pkgName, subscribeId, callingPid)  ← L944       │
│    └─ InnerStopDiscovery()                            ← L878       │
│          ├─ 加锁                                                    │
│          ├─ RemoveDiscInfoFromCapabilityList()  从匹配桶移除        │
│          ├─ CallInterfaceByMedium(STOPDISCOVERY_FUNC)               │
│          │     ├─ ACTIVE  → interface->StopAdvertise()             │
│          │     └─ PASSIVE → interface->Unsubscribe()               │
│          ├─ ListDelete()  从发现链表删除节点                        │
│          ├─ info->item->infoNum--  减少引用计数                     │
│          └─ 解锁                                                    │
└─────────────────────────────────────────────────────────────────────┘

核心数据结构关系

g_discoveryInfoList (SoftBusList)
  │
  ├─ DiscItem (按 pkgName 分组)
  │     ├─ packageName: "com.example.app"
  │     ├─ pid: 12345
  │     ├─ callback: { serverCb, innerCb }
  │     ├─ infoNum: 引用计数
  │     │
  │     └─ InfoList ──┬─ DiscInfo (subscribeId=1, capability=bit7, mode=ACTIVE)
  │                   ├─ DiscInfo (subscribeId=2, capability=bit3, mode=PASSIVE)
  │                   └─ ...
  │
  │  同时,每个 DiscInfo 也挂到对应的 capability 桶中:
  │
  ▼
g_capabilityList[0~15] (16个链表头)
  │
  ├─ [0]  → (订阅 hicall 的 DiscInfo)
  ├─ [3]  → (订阅 castPlus 的 DiscInfo)
  ├─ [7]  → (订阅 osdCapability 的 DiscInfo) → DiscInfo → ...
  ├─ [9]  → (订阅 approach 的 DiscInfo)
  └─ ...

  匹配时: device->capabilityBitmap[bit] → g_capabilityList[bit] → 通知所有订阅者

完整业务流程总结

初始化:  DiscServerInit → DiscMgrInit
           → 注册回调 + 初始化介质 + 创建链表 + 初始化匹配桶

运行期:
  启动发现 → InnerStartDiscovery
               → 注册到 g_discoveryInfoList
               → 注册到 g_capabilityList[bit]
               → 介质层开始监听

  设备匹配 → DiscOnDeviceFound
               → bitmap 位匹配 g_capabilityList[bit]
               → InnerDeviceFound → 回调通知订阅者

  停止发现 → InnerStopDiscovery
               → 从 g_capabilityList[bit] 移除
               → 介质层停止监听
               → 从 g_discoveryInfoList 删除

异常处理: DiscServerDeathCallback → DiscMgrDeathCallback
               → 清理死亡进程的所有发布和发现

反初始化: DiscServerDeinit → DiscMgrDeinit
               → 清理全部资源 + 反初始化介质

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐