tips

分布式软总线的能力位图底层设计实现其实就是侵入式链表,没这方面基础的见链表学习(侵入式链表)-CSDN博客

功能

能力位图机制是软总线的能力资源管理的核心,管理软总线所有已发布能力的聚合以及相关订阅者,但是别被误导了,上面功能不是有一张表管理,open Harmony在这方面拆的很细。

一、核心概念

能力位图(Capability Bitmap) 是发现模块中用来标识和匹配设备能力的机制。用一个 uint32_t 的每一位表示一种能力,支持 14 种能力(bit 0~13)。

二、能力位图在系统中的三套数据结构

整个发现模块中,能力位图相关的设计分布在两层、三套结构中:

三、三套结构详解

① Manager 层:g_capabilityList[16] — 能力分发索引

static ListNode g_capabilityList[CAPABILITY_MAX_BITNUM];  // 16个链表

本质:以能力位为下标的倒排索引,每个槽位挂载关注该能力的订阅者链表。

g_capabilityList[0]  (hicall)    → 空
g_capabilityList[1]  (profile)   → 空
g_capabilityList[2]  (visionPic) → 空
g_capabilityList[3]  (castPlus)  → 空
g_capabilityList[4]  (aa)        → 空
g_capabilityList[5]  (dvKit)     → 空
g_capabilityList[6]  (ddmp)      → DiscInfo(AppD订阅) → DiscInfo(AppE订阅)
g_capabilityList[7]  (osd)       → 空
g_capabilityList[8]  (share)     → DiscInfo(AppF订阅)
g_capabilityList[9]  (approach)  → 空
g_capabilityList[10] (vlink)     → 空
g_capabilityList[11] (touch)     → DiscInfo(AppG订阅)
g_capabilityList[12] (oop)       → 空
g_capabilityList[13] (oh_appr)   → 空
g_capabilityList[14]            → 空
g_capabilityList[15]            → 空

核心操作

操作 时机 逻辑
AddDiscInfoToCapabilityList 订阅者注册 遍历订阅者的 bitmap,每个置1的位 → 挂到对应链表
RemoveDiscInfoFromCapabilityList 订阅者注销 从链表中摘除该节点
DiscOnDeviceFound 远端设备被发现 遍历设备的 bitmap,每个置1的位 → 遍历对应链表 → 回调订阅者

② CoAP 层:g_publishMgr — 发布能力聚合器

typedef struct {
    bool isUpdate;                    // 能力是否有变化(需要重新注册到NSTACKX)
    bool isEmpty;                     // 是否已全部清空
    int16_t capCount[MAX_CAP_NUM];   // 每个能力的发布者数量(引用计数)
    uint32_t allCap[CAPABILITY_NUM]; // 聚合后的总能力位图
    SoftBusMutex lock;
} DiscCoapInfo;

static DiscCoapInfo *g_publishMgr = NULL;

本质:多发布者的能力合并器,用引用计数管理能力的生命周期。

核心操作

操作 时机 逻辑
RegisterAllCapBitmap 发布者注册 遍历发布者的 bitmap,每个置1的位 → capCount++,首次置1时 allCap 置位
UnregisterAllCapBitmap 发布者注销 遍历发布者的 bitmap,每个置1的位 → capCount--,归零时 allCap 清位
DiscCoapRegisterCapability(allCap) allCap 变化时 将聚合位图注册到 NSTACKX,驱动 CoAP 广播

引用计数的作用

App A Publish(share)  → capCount[8]=1, allCap |= (1<<8) → 广播 "我有share"
App B Publish(share)  → capCount[8]=2, allCap 不变       → 广播内容不变
App A UnPublish       → capCount[8]=1, allCap 不变       → 广播内容不变(B还在发布)
App B UnPublish       → capCount[8]=0, allCap 清除bit8  → 停止广播share能力

③ CoAP 层:g_subscribeMgr — 订阅能力聚合器

结构与 g_publishMgr 完全相同,但语义不同

g_publishMgr g_subscribeMgr
capCount 含义 有多少发布者发布了该能力 有多少订阅者订阅了该能力
allCap 含义 本地设备对外声明的总能力 本地设备扫描远端的总过滤器
allCap 驱动 DiscCoapRegisterCapability → 广播 DiscCoapSetFilterCapability → 设置扫描过滤
计数归零 停止广播该能力 停止过滤/扫描该能力

四、完整结构关系图

┌─────────────────────────────────────────────────────────────────────────┐
│                        应用层 (SDK)                                     │
│                                                                        │
│   App A ─── Publish(ddmp)                                              │
│   App B ─── Publish(share)                                             │
│   App C ─── Publish(ddmp + share)                                      │
│   App D ─── Subscribe(ddmp)                                            │
│   App E ─── Subscribe(ddmp + touch)                                    │
│   App F ─── Subscribe(share)                                           │
└────────┬────────────────────────────────────────────────┬───────────────┘
         │ 发布                                        │ 订阅
         ▼                                            ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                     Manager 层 (disc_manager.c)                         │
│                                                                        │
│  ┌── g_publishInfoList ──────────────┐  ┌── g_discoveryInfoList ──────┐│
│  │                                    │  │                             ││
│  │  DiscItem(AppA)                    │  │  DiscItem(AppD)             ││
│  │   └─ DiscInfo: Publish(ddmp)      │  │   ├─ DiscInfo: Sub(ddmp)   ││
│  │                                    │  │   └─ capNode → capList[6]  ││
│  │  DiscItem(AppB)                    │  │                             ││
│  │   └─ DiscInfo: Publish(share)     │  │  DiscItem(AppE)             ││
│  │                                    │  │   ├─ DiscInfo: Sub(ddmp+   ││
│  │  DiscItem(AppC)                    │  │   │     touch)              ││
│  │   └─ DiscInfo: Publish(ddmp+share)│  │   ├─ capNode → capList[6]  ││
│  │                                    │  │   └─ capNode → capList[11] ││
│  └────────────┬───────────────────────┘  │                             ││
│               │ 转发到底层                 │  DiscItem(AppF)             ││
│               ▼                           │   ├─ DiscInfo: Sub(share)   ││
│  ┌── g_capabilityList[16] ──────────┐    │   └─ capNode → capList[8]  ││
│  │ 能力分发索引(只挂订阅者)           │    │                             ││
│  │                                  │    └──────────────┬──────────────┘│
│  │  [6]  ddmp  → AppD → AppE       │                   │              │
│  │  [8]  share → AppF              │                   │              │
│  │  [11] touch → AppE              │                   │              │
│  │  其他 → 空                       │                   │              │
│  └──────────────────────────────────┘                   │              │
│         ▲                                              │              │
│         │ 远端设备被发现时查表分发回调                    │              │
└─────────┼──────────────────────────────────────────────┼──────────────┘
          │                                              │
          ▼                                              ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                     CoAP 层 (disc_coap.c)                               │
│                                                                        │
│  ┌── g_publishMgr ─────────────────┐  ┌── g_subscribeMgr ─────────────┐│
│  │ 发布能力聚合器                    │  │ 订阅能力聚合器                 ││
│  │                                  │  │                               ││
│  │ capCount[6]  = 2  (AppA+AppC)   │  │ capCount[6]  = 2  (AppD+AppE) ││
│  │ capCount[8]  = 2  (AppB+AppC)   │  │ capCount[8]  = 1  (AppF)      ││
│  │ capCount[11] = 0                 │  │ capCount[11] = 1  (AppE)      ││
│  │                                  │  │                               ││
│  │ allCap = ddmp | share            │  │ allCap = ddmp | share | touch ││
│  │       = (1<<6)|(1<<8) = 0x0140  │  │       = 0x0900 | 0x0400      ││
│  │                                  │  │       = 0x0D40               ││
│  │         │                        │  │         │                     ││
│  │         ▼                        │  │         ▼                     ││
│  │  DiscCoapRegisterCapability      │  │  DiscCoapSetFilterCapability  ││
│  │  → 注册到NSTACKX                │  │  → 设置NSTACKX扫描过滤器      ││
│  │  → 驱动CoAP多播广播              │  │  → 驱动CoAP扫描               ││
│  └──────────────────────────────────┘  └───────────────────────────────┘│
│                                                                        │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │  NSTACKX (DFinder)                                               │  │
│  │                                                                  │  │
│  │  广播: CoAP多播 → "本地有 ddmp+share 能力"                        │  │
│  │  扫描: CoAP扫描 → 过滤 "只关注有 ddmp+share+touch 的远端设备"     │  │
│  └──────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────┘

五、数据流:从注册到发现的完整链路

六、三套结构的对比总结

维度 ① g_capabilityList ② g_publishMgr ③ g_subscribeMgr
所在层 Manager CoAP CoAP
数据结构 ListNode[16] 链表数组 DiscCoapInfo 含引用计数 DiscCoapInfo 含引用计数
挂载内容 订阅者 DiscInfo 发布者的能力位图 订阅者的能力位图
核心语义 "谁在关注每个能力" "本地声明了哪些能力" "本地在扫描哪些能力"
用途 设备发现时分发回调 聚合后驱动广播 聚合后驱动扫描过滤
引用计数 无(链表本身即计数) 有(capCount) 有(capCount)
方向 内部分发(本地→本地) 对外广播(本地→远端) 对内过滤(远端→本地)

一句话总结

g_publishMgr 聚合发布能力去广播"我是谁",g_subscribeMgr 聚合订阅能力去扫描"找谁谁",g_capabilityList 是发现事件到达时的倒排索引,把"找到了谁"精准分发给"谁在找"。

七、allcap计算

比如当多个应用发布不同能力的时候,coap层聚合他们

App A 发布: capabilityBitmap = share (bit 8)
App B 发布: capabilityBitmap = ddmp  (bit 6)
App C 发布: capabilityBitmap = share (bit 8) + touch (bit 11)

聚合结果:
  capCount[6]  = 1   (ddmp, 只有B发布)
  capCount[8]  = 2   (share, A和C都发布)
  capCount[11] = 1   (touch, 只有C发布)
  allCap = (1<<6) | (1<<8) | (1<<11) = 0x0900  ← 聚合位图

(1<<6)-->0000 0000 0100 0000

  (1<<8)  -->0000 0001 0000 0000

 (1<<11)  -->0000 1000 0000 0000

------------------------------------------------三个相或

结果:        0000 1001 0100 0000

逐位对照:

结果转换成16进制:0x0940

哪个能力开启就把哪个位置置1,0x0940就是三个能力全开启。

Logo

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

更多推荐