分布式软总线核心代码分析(二)
(发现服务)
前言
经过本人分析,我下载的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
→ 清理全部资源 + 反初始化介质
更多推荐
所有评论(0)