OpenHarmony 技术拆解(二):从 capability 看懂分布式软总线与任务迁移

多设备协同里最容易被低估的问题,是系统怎样描述一台设备能做什么。

如果两台设备只是互相发一段数据,普通网络栈已经足够。真正复杂的是:设备 A 附近可能有手机、手表、平板、电视、音箱;每台设备都可能提供不同能力;同一台设备上还可能同时有投屏、音频、文件分享、分布式调度、设备虚拟化等能力。系统不能让每个业务自己去理解附近所有设备,也不能让每个业务自己维护一套发现协议。

所以 OpenHarmony 分布式软总线的第一个关键抽象,不是连接,也不是传输,而是 capability。

capability 可以理解成软总线里的能力索引。它回答的是一个很基础的问题:当前业务到底要找哪一类设备能力。

发现层围绕 capability 建表,介质层围绕 capability 发包,回调层围绕 capability 分发结果。把这个抽象讲清楚,DSoftBus 的发现、组网、传输和 DMS 任务迁移就顺了很多。


1. capability 不是普通字符串,而是系统索引

从业务角度看,capability 像一个能力名。例如投屏、分享、分布式中间件、设备虚拟化等能力,都需要一个可识别的名字。

但在软总线内部,它不只是字符串。

OpenHarmony 里会把能力名映射成固定的 bitmap 位。公开接口中能看到一组固定映射:hicall 对应 bit 0,profile 对应 bit 1,castPlus 对应 bit 3,ddmpCapability 对应 bit 6,share 对应 bit 8,virtualLink 对应 bit 10,touch 对应 bit 11,raiseHand 对应 bit 15。

这组映射可以看成软总线发现层的能力字典。业务传入能力名,系统查字典得到 bit 位,再用 bit 位完成索引、过滤和广播承载。

这个转换看起来只是工程实现细节,实际上是发现系统的核心设计。

字符串适合给业务看,bitmap 适合给系统做快速匹配和低成本承载。

如果一直用字符串做发现匹配,会遇到几个问题:

  • 比较成本高,发现事件频繁时不划算。

  • 多能力组合不好表达。

  • BLE 广播包、COAP 报文这类承载空间有限,不适合塞长字符串。

  • 订阅关系很难高效索引。

bitmap 则刚好解决这些问题。一位代表一种能力,一组位代表一组能力。判断某个设备是否具备某种能力,本质上就是位运算:远端设备携带一组能力 bit,本地订阅也携带一组能力 bit,两者做与运算;结果非零,说明这台设备命中了当前业务订阅。

这就是 capability 设计的第一层意义:把业务语义压缩成系统可快速匹配的索引。


2. 为什么发现系统需要 capability,而不是发现设备后再判断

一种直觉做法是:先把附近设备都发现出来,再让业务自己判断哪些设备能用。

这个做法在小 demo 里可行,在系统服务里会迅速失控。

原因很简单:发现是公共资源。Wi-Fi、BLE、USB、近场广播都不是无限资源。频繁扫描会影响功耗,广播内容受长度限制,多个业务同时发现时还会互相干扰。

所以系统更合理的设计是:业务先告诉软总线它关心什么能力,软总线再决定如何用底层介质去发现。

这就变成了一个发布订阅模型。

发布方把本机能力交给软总线,订阅方把目标能力交给软总线;软总线把两边都转换成 bitmap,再由发现管理器登记订阅关系并选择介质开始发现。

这个模型里,capability 是连接业务语义和底层发现协议的桥。

业务侧看到的是能力。

发现管理器看到的是订阅表和 bitmap。

介质适配器看到的是要广播或扫描的压缩字段。

回调分发器看到的是发现结果里的 capabilityBitmap。

一层层向下,语义越来越压缩;一层层向上,结果又恢复成业务能理解的设备事件。


3. capability 在发现链路里怎么流动

一次发现请求进入 DSoftBus 后,大致会经历五步。

第一步,校验参数。

系统会检查发现模式、介质类型、频率、能力数据长度。capabilityData 必须是 C 字符串格式,长度不能超过限制。这个限制不是随便来的,因为发现数据最终可能进入广播包、COAP 数据、BLE service data 等承载,不能无限增长。

第二步,把 capability 字符串转换成 bitmap。

如果业务传入 castPlus,系统会在能力映射表里找到对应 bit,然后把这个 bit 写入 capabilityBitmap。如果传入系统不认识的能力名,请求会失败。

第三步,把订阅请求挂到能力链表上。

DSoftBus 发现管理器内部维护了按能力划分的订阅链表。例如 bit 3 对应 castPlus 订阅链表,bit 6 对应 ddmpCapability 订阅链表,bit 8 对应 share 订阅链表。设备发现后命中哪个 bit,就进入对应链表回调。

这样设备被发现时,不需要遍历所有业务,只需要看设备携带了哪些 bit,再进入对应链表回调。

第四步,选择介质适配器。

业务请求里会带 medium,例如 COAP、BLE、USB 或 AUTO。发现管理器不会自己操作网络和蓝牙,它会把内部选项交给对应介质适配器。

AUTO 不是神秘能力,本质是系统同时尝试多个可用介质。COAP 适合局域网能力发现,BLE 适合近场发现,USB 适合特定连接场景。不同介质承载不同,但上层都围绕同一套 capability 抽象。

第五步,发现结果回调。

介质层发现设备后,会带回设备信息和 capabilityBitmap。发现管理器遍历 bitmap,找到对应订阅链表,再把设备事件回调给业务。

完整链路可以读成:业务能力名先进入 capability bitmap,再进入发布/订阅表;介质适配器负责对外发布或扫描;发现结果回来后,发现管理器按 capability list 定向分发给业务回调。

这条链路才是设备发现的核心。

!外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Finternal-api-drive-stream.feishu.cn%2Fspace%2Fapi%2Fbox%2Fstream%2Fdownload%2Fauthcode%2F%3Fcode%3DYzFjOGQzY2Y3MzllNTkzYjc1Mzk5YWY1ODQ1M2UwYjJfNmJlZmUzZDA5YjRiMDhiNjcwNmEzZTAzYzAxOGNhMzVfSUQ6NzY0OTc4OTk2NzM5MjMxMjI4OV8xNzgxMTA4MDQwOjE3ODExOTQ0NDBfVjM\&pos_id=img-IEZkwvaq-1781140605328

4. capabilityData 是干什么的

capability 解决的是粗粒度分类。它告诉系统这类能力是什么。

但很多场景只靠一个能力名不够。例如同样是投屏能力,可能还要表达协议版本、业务扩展字段、设备形态、是否支持某种模式。同样是分享能力,也可能需要携带业务侧自定义数据。

这就需要 capabilityData。

capability 和 capabilityData 的关系是:capability 负责粗分类,决定是否属于同一类能力;capabilityData 负责细节描述,例如协议版本、设备形态、业务扩展字段。

这也是为什么接口里同时有 capability 和 capabilityData。

capability 进入系统映射表,转成 bitmap,参与索引和匹配。

capabilityData 被复制保存,并交给底层介质适配器组装到发现数据里。COAP 可以承载更丰富的业务数据,BLE 广播包空间更紧张,通常要做更强的压缩或只放必要字段。

这里的设计取舍很明确:

  • capability 必须稳定,不能随业务随意扩散,否则系统映射表和介质承载都会失控。

  • capabilityData 可以灵活一些,但要受长度、格式和安全约束。

  • 粗分类用 bitmap 做高效匹配,细节数据交给业务或介质层进一步解析。

这就是软总线发现层既能统一调度,又能保留业务扩展能力的原因。


5. capability 的边界怎么划

capability 不能被设计成业务随便扩展的字符串池。

如果每个业务都能随手新增一个 capability,发现层很快会遇到三个问题。

第一,系统索引会膨胀。bitmap 位是有限资源,每个 bit 都代表一种系统认可的能力类型。它更像内核里的设备类别或协议族,不适合承载无限业务标签。

第二,介质承载会变复杂。BLE、COAP、USB 等介质都要理解这些能力位。能力集合越随意,介质适配层越难保持一致。

第三,权限和安全边界会变模糊。能力发现不是普通应用内事件,而是跨设备入口。某个 capability 是否允许被发现、是否允许唤醒远端、是否需要同账号或绑定关系,都应该有系统级约束。

所以更合理的边界可以按三层划分:系统级能力类别放 capability,业务级细分参数放 capabilityData,一次性会话参数留到后续 session 或 DMS 命令里协商。

比如投屏能力本身适合成为 capability。投屏协议版本、设备形态、是否支持某种画质模式,更适合放在 capabilityData。某次投屏连接的 token、窗口参数、会话状态,不应该塞进发现包,而应该在组网后的安全通道里协商。

这个边界很关键。发现包只负责让对端知道这里有一类能力,不负责完成全部业务协商。

6. capability 匹配更像索引命中,不像业务判断

发现结果从介质层回来时,通常已经带着 capabilityBitmap。发现管理器要做的不是理解业务,而是做索引命中。

它更像一个倒排索引:bit 3 对应 castPlus 的订阅者列表,bit 6 对应 ddmpCapability 的订阅者列表,bit 8 对应 share 的订阅者列表。

远端设备上报 capabilityBitmap 后,系统逐位检查。命中 bit 3,就去 bit 3 对应的订阅链表里回调;命中 bit 8,就去 bit 8 的订阅链表里回调。

这解释了为什么 capability 要先转 bitmap。它不是为了炫技,而是为了让发现管理器不需要理解业务含义,只需要做高效路由。

业务真正的判断会发生在回调之后。比如收到一个 share 设备后,业务还可以再看 capabilityData、设备类型、账号关系、版本信息,决定是否展示给用户或继续连接。

这样分层以后,软总线发现层负责快速发现、粗粒度过滤、事件分发;业务层负责细粒度兼容性判断和交互决策。

7. 为什么要维护能力计数

多个业务可能同时订阅同一种能力。

如果每个业务订阅一次,底层就启动一次 BLE 扫描或 COAP 发现,系统资源会被浪费,功耗也会变差。

所以能力在介质层通常需要聚合。

引用计数的逻辑是:第一个业务订阅某能力时启动底层发现,后续业务订阅只增加计数;取消订阅时计数递减,直到归零才停止底层发现。

COAP 适配中可以看到类似 capCountallCap 的设计。capCount 记录每种能力被多少调用方需要,allCap 是当前介质层真正需要发布或订阅的能力集合。

这个设计很重要。它让发现系统从应用私有行为变成系统级资源调度。

业务只表达需求,系统负责合并需求、选择介质、控制功耗和回调分发。

8. BLE 为什么更依赖 bitmap

BLE 广播包空间很有限,不能像普通网络报文那样随便塞长字段。软总线在 BLE 场景里会把能力放到 service data 的特定位置,例如一个字节或少数字段里表示 capability bitmap。

这解释了为什么 capability 不能只停留在字符串设计。

如果设备要通过 BLE 告诉周围设备自己具备 castPlus、dvKit、osdCapability 等能力,最经济的方式不是广播多个字符串,而是广播一组 bit。

接收方拿到 BLE 广播数据后,先解析 capability 位,再和本机订阅能力做交集。如果没有交集,甚至可以不继续处理后续业务数据。

这就是典型的快速预过滤。

BLE 场景的处理顺序是先解析 capability 位,再和本机订阅位做交集;命中后才继续解析业务数据。

这种设计对功耗和性能都更友好。附近设备很多时,系统可以用非常低的成本过滤掉无关广播。


9. COAP 里的 capability 更像局域网服务摘要

COAP 场景和 BLE 不同。它通常运行在局域网发现语境下,承载空间比 BLE 宽松一些,但也不能无限制扩张。

COAP 适配层同样要维护当前发布和订阅的能力集合。它要知道当前本机有哪些能力需要发布到网络里,也要知道本机正在寻找哪些能力。

因此 COAP 里的 capability 更像服务摘要。

  • 本机能力集合发生变化时,需要更新发布数据。

  • 订阅集合发生变化时,需要更新发现过滤条件。

  • 远端设备上报时,先看 capability 是否命中,再把设备信息交给上层。

如果说 BLE 更强调短包压缩和近场低功耗,那么 COAP 更强调局域网内的服务摘要传播和发现结果聚合。

两种介质差异很大,但上层都被收敛到同一个 capability 模型。

这就是抽象层的价值。


10. 从 capability 到 networkId:发现不是终点

capability 只回答对端具备什么能力,不回答对端是否可信,也不回答后续通信走哪条链路。

所以发现之后还要进入认证和组网。

发现阶段拿到的设备信息,更多是候选对象。系统还要确认:

  • 这个设备是否属于可信关系。

  • 是否满足同账号、绑定、权限等条件。

  • 是否允许被唤醒或被拉起。

  • 是否能加入逻辑网络。

组网成功后,上层拿到的关键标识不再是发现阶段的临时地址,而是 networkId。networkId 是逻辑网络里的设备标识,后续 DMS 发起远程启动、迁移、绑定时,都应该围绕 networkId 工作。

这里存在两次抽象转换:先把业务能力名转换成 capability bitmap,再把发现阶段的物理设备信息转换成逻辑网络里的 networkId。

第一次转换让系统知道要找什么能力。

第二次转换让系统可以稳定引用这个设备。

如果缺少第一层,发现会变成无差别扫描和广播。

如果缺少第二层,上层业务会被 IP、蓝牙地址、链路变化拖着走。


11. lane 解决的是通信路线,而不是能力发现

capability 和 lane 经常会被混在一起理解。

其实它们解决的问题完全不同。

capability 用在发现阶段,负责回答要找什么能力。

lane 用在传输阶段,负责回答数据该走哪条通信路线。

例如一个业务订阅 ddmpCapability,发现到一台可信设备,完成组网后准备发送任务迁移数据。此时 capability 的作用已经基本结束,接下来要根据数据类型、QoS、网络状态选择 lane。

三者分工可以这样记:发现阶段由 capability 决定候选设备,组网阶段由 networkId 确定逻辑节点,传输阶段由 lane 决定通信路线。

这个分工很重要。否则文章里堆很多名词,但读者不知道每个抽象到底在哪个阶段生效。


12. 设备发现不是一次回调,而是一条过滤流水线

前面讲 capability 时,重点放在能力如何索引。但真正落到 DSoftBus,设备发现不是介质层收到一个广播包就直接通知业务。

它更像一条过滤流水线:从底层广播包开始,依次经过协议合法性过滤、版本和 UUID 过滤、capability 预过滤、accountHash 预判断、广播包去重、地址和距离信息转换、DeviceInfo 归一化,最后才交给发现管理器和 LNN。

这条链路的目标不是尽可能多地上报设备,而是尽可能早地过滤掉无关设备。

以 BLE 为例,扫描回来的数据会先做基础合法性检查:广播数据是否完整、payload 是否存在、类型是否是 service data、service uuid 是否匹配、版本是否匹配。如果这些基础字段都不对,后面没有必要继续解析。

通过基础检查后,才会进入服务数据解析。BLE service data 通常由 version、accountHash、capability bit 和 TLV 扩展字段组成。version 用来判断协议版本,accountHash 用来做账号关系预判断,capability bit 用来做能力预过滤,TLV 用来承载设备名、设备类型、地址、业务扩展数据等可变信息。

这就是 BLE 发现依赖短字段的原因。它不能像 TCP 连接建立后那样慢慢交换大块 JSON,必须在很小的广播包里先完成粗过滤。

13. 设备发现里的去重为什么重要

附近设备的广播不是只来一次。BLE 广播会周期性出现,COAP 发现也可能反复收到同一台设备的上报。

如果发现层每收到一次包就回调业务,上层会看到大量重复设备事件,功耗和 UI 都会被拖垮。

所以 DSoftBus 会在发现链路里做重复过滤。BLE 场景里可以看到一种做法:把广播 payload 和响应 payload 拼起来计算 hash,再用这个 hash 判断是否已经处理过类似消息。

这一步的意义不是安全校验,而是事件降噪。

去重链路可以理解成:广播包内容先生成 packet hash,再进入最近接收表;如果命中重复记录,就丢弃或降频处理。

重复过滤之后,系统才会继续做地址转换、距离估算和结果上报。

地址转换也不是多余动作。底层拿到的可能是二进制 BLE MAC,业务和上层账本更适合处理标准字符串形式。距离估算则会结合 RSSI 和广播功率,给上层一个粗略 range,用于近场设备展示或策略判断。

最后上报的不是原始广播包,而是归一化后的 DeviceInfo。

DeviceInfo 里通常包含:

  • devId:设备标识摘要或发现阶段可用的设备 ID。

  • accountHash:账号哈希,用于同账号快速判断。

  • capabilityBitmap:设备发布的能力集合。

  • addr:连接地址信息,例如 BLE 地址、IP 地址等。

  • deviceName / deviceType:展示和策略判断需要的设备信息。

  • range:距离估计。

介质层把这些字段整理好后,会调用统一的 OnDeviceFound 回调,把设备交给发现管理器。

14. 发现管理器怎么把设备分给正确业务

发现管理器不应该理解投屏、分享、迁移这些业务含义。它只做一件事:按 capability 分发。

前面提到过,订阅请求会挂到 capability list 上。设备被发现后,发现管理器遍历设备的 capabilityBitmap,命中哪个 bit,就进入哪个订阅链表。

发现管理器读取 DeviceInfo.capabilityBitmap 后,按 bit 位进入对应订阅链表,例如 castPlus、share、ddmpCapability 分别对应不同业务回调列表。

这个分发过程有两个细节。

一是区分内部模块和普通业务。内部模块可以拿到更靠近系统侧的回调,普通业务则通过 server callback 回到自己的包名和 subscribeId。

二是发现结果会带 additions。比如 medium 表示这个设备是通过 BLE、COAP 还是 USB 被发现的。这个字段会影响后续认证和连接策略。通过 BLE 发现的设备,不代表后续数据一定走 BLE;它只是告诉系统最初是从哪条发现路径看到这个设备。

所以设备发现不是发现即连接。发现只是把候选设备交给 LNN 和 Auth 继续处理。

15. 从 DeviceInfo 到 LNN:发现结果如何进入组网

DSoftBus 里还有一个容易混淆的概念:发现层和组网层不是一回事。

发现层负责找到候选设备。

LNN 负责把可信设备组织成逻辑网络。

LNN 可以理解成 Logical Node Network,逻辑节点网络。它维护本机和远端设备的节点信息,也就是后面经常看到的分布式账本。

发现层上报 DeviceInfo 后,LNN 不会直接把它变成在线节点。它还要判断这台设备是否值得认证:

  • devId 是否有效。

  • accountHash 是否和本机同账号。

  • 本地是否存在可信设备关系。

  • 设备是否可能属于点对点可信关系。

  • 当前介质是否适合发起认证连接。

这里会用到 potential trusted 这类判断。它不是最终认证结果,只是决定要不要继续走认证流程。

可以把它理解成门口保安的第一眼检查:看证件格式、看是否像同一组织、看是否在历史可信名单里。通过这一步,才进入真正认证。

16. 认证不是登录,而是建立可信通信上下文

DSoftBus 的认证不是让用户输入账号密码。它解决的是设备之间能不能建立可信通信上下文。

认证阶段会依次确认对端设备身份、判断双方可信关系、协商或恢复 session key、加密交换设备信息、写入分布式账本,并最终形成 networkId。

这里有几个关键对象。

AuthConnInfo 表示认证连接信息。它描述这次认证走什么链路,例如 Wi-Fi、BLE、BR、USB 等。

AuthSessionInfo 表示一次认证会话的上下文。里面会包含本次连接信息、设备 UUID、UDID、版本、是否服务端、压缩能力等。

AuthHandle 表示认证通道句柄。后续加密传输和关闭连接时都靠它定位具体认证连接。

SessionKey 是认证后用于加密通信的会话密钥。设备信息交换时不是明文裸奔,而是通过 session key 做加密和解密。

17. 认证链路里真正交换了什么

一次认证链路通常会先交换设备 ID,再交换设备信息。

设备 ID 阶段用于确认对端是谁。不同链路和版本会有不同封装方式,老版本可能直接传设备 ID,新版本会走 JSON 格式。这里会涉及 UUID、UDID 或它们的 hash。

设备信息阶段更关键。DSoftBus 会把本机 NodeInfo、连接信息、版本能力等打包成 device info message。这个消息可能会先压缩,再通过 session key 加密,然后通过认证连接发给对端。

对端收到加密 device info 后,会根据 authSeq 找到 session key,完成解密和必要的解压,再解析 NodeInfo 并更新远端节点信息。

这样做有两个好处。

第一,发现包里只放少量摘要字段,不暴露完整设备信息。

第二,完整设备信息只在认证通道里交换,并且受 session key 保护。

这就是发现和认证的分工:发现阶段负责低成本找到候选设备,认证阶段负责安全地确认身份并交换完整节点信息。

18. networkId 是认证组网之后的逻辑身份

认证成功后,系统不会让上层继续拿 BLE MAC 或 IP 地址工作。

底层地址会变,链路会切,设备可能先通过 BLE 被发现,后续通过 WLAN 传输。如果上层直接绑定物理地址,分布式业务会非常脆弱。

所以 LNN 会在分布式账本里维护远端节点,并给上层一个 networkId。

networkId 是逻辑网络里的设备身份。DMS、传输层、lane 选择后续都围绕 networkId 工作。

身份转换可以分成四段:发现阶段是 DeviceInfo、devId、accountHash、addr;认证阶段是 UUID、UDID、session key、NodeInfo;组网完成后是 networkId 和分布式账本;业务阶段由 DMS 使用 networkId 发起任务迁移。

这样一来,上层不用关心设备当前到底是走 BLE、Wi-Fi 还是 P2P。上层只需要说我要和这个 networkId 对应的设备通信,软总线再负责选择链路。

19. DMS 到底是什么意思

DMS 可以理解成 Distributed Mission Scheduler,也就是分布式任务调度服务。

它不负责底层发现,也不直接管理 Wi-Fi、BLE、P2P 这些链路。DMS 站在更上层,处理的是任务和组件生命周期。

在 OpenHarmony 里,一个用户正在使用的页面或任务,通常不是单独看成一个进程,而是和 Ability、Mission、Bundle 这些概念绑定在一起。

DMS 要回答的问题是:

  • 当前这个任务属于哪个应用包。

  • 当前任务对应哪个 Ability。

  • 这个 Ability 是否声明支持继续。

  • 目标设备上有没有对应应用和可恢复入口。

  • 源端保存出的状态能不能被目标端恢复。

  • 迁移成功后源端任务要保留还是清理。

所以 DMS 不是软总线的替代品。它是软总线之上的调度层。

DSoftBus 解决设备之间如何可信通信,DMS 解决任务如何跨设备继续运行。前者是通信底座,后者是任务调度层。

DMS 需要 DSoftBus 提供通道,但 DMS 真正关心的是任务状态、应用身份、Ability 入口、权限校验和失败回滚。

20. Bundle 是什么,为什么迁移绕不开它

Bundle 可以理解成 OpenHarmony 里的应用包身份和组件清单。

一个 Bundle 不是只有安装包名字。它背后包含很多对系统很关键的信息:

  • bundleName:应用包名,标识这是哪个应用。

  • versionCode:应用版本,用于判断源端和目标端是否兼容。

  • abilityInfos:这个应用声明了哪些 Ability。

  • moduleName:Ability 所在模块。

  • continueType:哪些 Ability 支持哪类任务继续。

  • developerId / appIdentifier:开发者和应用身份,用于跨设备、跨 Bundle 权限判断。

任务迁移时,源端不能只告诉目标端打开某个页面。目标端必须先确认本机是否有对应 Bundle,以及这个 Bundle 里是否存在能处理该 continueType 的 Ability。

这一步非常像动态链接前的符号解析:源端说我要继续某类任务,目标端要在自己的组件清单里找到能接住这个任务的入口。

DMS 里会通过 BundleManager 或分布式 Bundle 信息查询目标 Bundle。它不是为了走流程,而是为了防止几类问题:

  • 目标设备没装这个应用。

  • 目标应用版本太低,无法理解源端状态。

  • 目标 Ability 不支持对应 continueType。

  • 源端和目标端不是同一个应用身份,也不是可信的同开发者关系。

  • 调用方没有权限启动目标 Ability。

因此,Bundle 在任务迁移里承担的是身份、版本、组件入口和权限边界。

21. Want 和 WantParams 是迁移状态的载体

理解 Bundle 后,还要理解 Want。

Want 可以理解成一次 Ability 启动或恢复请求的描述。它里面会包含目标 Bundle、Ability、moduleName,以及一组参数。WantParams 则承载具体业务参数。

任务迁移不是搬进程,而是源端 Ability 把可恢复状态写进 Want 或 WantParams,目标端再用这些数据启动或恢复 Ability。

这份状态要满足一个前提:能序列化,能跨设备解释。

适合放进去的内容包括页面入口、业务 ID、播放进度、文档位置、恢复模式。

不适合放进去的内容包括文件描述符、线程对象、解码器内部指针、本地硬件句柄。

DMS 的 DataCmd 里会带 Want、AbilityInfo、CallerInfo、AccountInfo。DataCmd 里的 Want 描述目标端恢复 Ability 所需的启动参数和业务状态;AbilityInfo 帮助目标端做组件匹配;CallerInfo 用于权限校验;AccountInfo 用于跨设备可信边界判断。

这比简单传一段 JSON 更严格。因为目标端不是普通服务,它要真正拉起系统 Ability,还要保证权限和应用身份正确。

22. DMS 任务迁移不是把进程搬走

讲完软总线,再看分布式任务迁移。

任务迁移容易被误解成进程迁移。OpenHarmony 的任务继续并不是把源设备上的进程内存、线程栈、文件描述符、硬件上下文整体搬到目标设备。它做的是 Ability 级别的状态保存和恢复。

更准确地说,迁移的是一份可恢复的业务状态。

这份状态通常放在 Want 或 WantParams 里,包含目标端恢复页面需要的参数。源端 Ability 负责把自己当前能恢复的业务状态交给框架,目标端 Ability 再根据这些参数恢复界面和业务上下文。

所以任务迁移的边界不是操作系统自动决定的,而是应用和框架共同定义的。

可以迁移的是:

  • 当前页面入口。

  • 页面参数。

  • 播放进度。

  • 文档位置。

  • 业务上下文标识。

  • 可以重新打开的数据引用。

不能直接迁移的是:

  • 线程栈。

  • 文件描述符。

  • 本地硬件设备句柄。

  • mmap 地址。

  • 解码器内部状态。

  • 只能在源设备存在的临时资源。

这也是为什么任务迁移不是魔法,而是一个状态保存和恢复协议。


23. 一次任务迁移到底传了什么

一次任务迁移可以看成四类信息的组合。

第一类是目标信息。

系统要知道迁到哪台设备、哪个 bundle、哪个 ability、哪种 continueType。这里的 bundleName 用来确定目标应用,continueType 用来确定目标应用里哪个 Ability 能接住这次继续。

第二类是校验信息。

目标设备要判断本机是否安装对应应用,Ability 是否存在,版本是否兼容,权限是否满足,设备状态是否允许继续。这里会涉及 BundleInfo、AbilityInfo、developerId、appIdentifier 等信息。

第三类是状态数据。

源端 Ability 保存出来的 WantParams 会作为迁移数据传到目标端。目标端用这些数据构造启动参数。

第四类是收尾策略。

目标端恢复成功后,源端是否退出,是否保留任务,是否清理 mission,都需要根据策略处理。

这四类信息不会一次性粗暴扔过去,而是通过 DMS 状态机分阶段传输。

迁移过程可以分成准备、握手、数据、恢复、收尾五段:先确认目标和连接,再确认目标端是否具备继续条件,随后传输 Want/WantParams,目标端启动或恢复 Ability,最后源端退出、保留或回滚。


24. StartCmd、ReplyCmd、DataCmd、EndCmd 其实是迁移协议

DMS 内部会把迁移过程拆成命令。

StartCmd 用来通知对端准备迁移。

ReplyCmd 用来返回对端校验结果。

DataCmd 用来传输真正的状态数据。它通常会包含 Want、AbilityInfo、CallerInfo、AccountInfo。

EndCmd 用来完成收尾确认。目标端恢复成功或失败后,源端根据结果清理 mission、保留任务或回滚。

这些命令跑在 SoftBus session 上。DMS 负责命令语义,DSoftBus 负责把字节送到对端。

这可以理解成三层:DMS 迁移协议负责 StartCmd、ReplyCmd、DataCmd、EndCmd;SoftBus 传输通道负责 session、socket、channel、lane;底层通信介质负责 WLAN、BLE、P2P 等真实链路。

软总线并不知道某个 DataCmd 里是页面状态还是业务参数。它只保证通道建立、数据送达、断开通知。DMS 才知道当前处于迁移的哪个阶段,收到命令后该推进状态还是回滚。

25. 为什么任务迁移必须是状态机

如果任务迁移只是本机函数调用,一个函数从头跑到尾就够了。

跨设备不行。

任意阶段都可能失败:

  • 设备发现到了,但组网失败。

  • 组网成功了,但 SoftBus session 打不开。

  • session 打开了,但目标端没有对应 Ability。

  • 目标端有 Ability,但版本不兼容。

  • 源端状态保存失败。

  • 数据传输失败。

  • 目标端恢复失败。

  • 目标端恢复成功,但 EndCmd 丢了。

所以 DMS 必须把迁移拆成状态机。每个阶段只处理当前允许的命令和超时事件。

状态机带来的好处是:

  • 源端和目标端职责清楚。

  • 每个阶段都能独立超时。

  • 失败后知道该回滚哪里。

  • 收到重复命令或乱序命令时能拒绝。

  • session 断开时能清理对应任务。

任务迁移难的不是发一个包,而是每一步失败后系统仍然保持一致。


26. Linux 复刻时应该先复刻 capability 模型

如果在 Linux 上复刻这套能力,第一步不应该是写 RPC。

RPC 只解决调用问题,不解决发现和系统资源调度。

更合理的起点是 capability registry。

这个 registry 至少要有四张表。

第一张是 capability map,维护能力名、bit 位、允许的介质、数据长度限制和解析器。它决定哪些能力是系统认可的,哪些能力可以通过 BLE 发布,哪些能力可以通过 mDNS/COAP 发布。

第二张是 publish table,记录调用方、capability bit、capabilityData、medium、freq 和引用计数。它表示本机当前正在对外发布哪些能力。

第三张是 subscribe table,记录调用方、capability bit、medium、filter 和 callback。它表示本机哪些业务正在寻找哪些能力。

第四张是 dispatch table,维护 capability bit 到 subscriber list 的映射。它用于把发现结果定向分发给订阅者。

有了这四张表,发现系统才具备软总线的基本形态。

27. Linux 复刻任务迁移时要先定义状态边界

任务迁移也不能一上来写远程启动。

先要定义什么状态可以迁移。

Linux 原型里可以定义 TaskDescriptor 描述 app_id、task_id、target_capability、restore_entry 和 version;定义 TaskState 描述可序列化参数、资源引用、进度和时间戳;再定义 MigrationPolicy 描述成功后源端是否退出、超时、回滚和权限策略。

命令层可以抽象成 Prepare、Accept 或 Reject、TransferState、RestoreResult、Finish。名字不重要,阶段边界更重要。

这和 OpenHarmony DMS 的 StartCmd、ReplyCmd、DataCmd、EndCmd 思路是一致的,只是名字不同。

这里最重要的不是命令名,而是边界:迁移的是可序列化状态,不是进程实体。

如果这个边界没定义清楚,后面一定会陷入状态不一致、资源无法恢复、失败无法回滚的问题。


28. 把整条链路串起来

现在可以把 DSoftBus 和 DMS 放在一条链路里看。

完整链路可以串成一条线:业务声明能力后进入 capability bitmap 和发布/订阅表,介质适配器完成发布或发现,发现结果按 bitmap 分发;LNN 判断潜在可信关系,Auth 建立认证通道并加密交换 NodeInfo,远端写入分布式账本形成 networkId;随后 lane 选择链路,SoftBus 建立 session,DMS 发送迁移命令,目标端恢复 Ability 状态,源端完成收尾或回滚。

这条链路里,每个抽象都有明确位置。

capability 解决能力索引问题。

capabilityData 解决能力细节描述问题。

Auth 解决可信关系和加密通信上下文问题。

networkId 解决逻辑设备标识问题。

lane 解决链路选择问题。

session 解决业务通道问题。

DMS 状态机解决任务迁移一致性问题。

理解这些抽象之间的分工,比记住一堆接口名更重要。


29. 最后总结

DSoftBus 发现层的关键不是发现设备,而是把业务能力变成系统可索引、可压缩、可路由的 capability。

capability 的设计同时服务三件事:

  • 给业务表达能力语义。

  • 给系统做订阅索引和快速匹配。

  • 给 BLE、COAP 等介质提供低成本承载字段。

分布式任务迁移的关键也不是远程启动,而是 Ability 级状态保存、跨设备命令协议、目标端恢复和失败回滚。

把这两层连起来看,OpenHarmony 分布式能力的主线其实很清楚:先用 capability 找到合适的能力节点,再用 networkId 稳定引用设备,然后通过 lane 和 session 建立通道,最后由 DMS 状态机完成任务继续。

相关推荐
OpenAnolis小助手17 小时前
如何利用 AI Agent 实现热补丁的自动化生成
人工智能·安全·ai·操作系统·agent·龙蜥
小宇子2B2 天前
缺页中断不是“出错”,是内核最忙的一条正常路径
操作系统
小宇子2B2 天前
内存不够时,内核怎么把"冷"页踢出去——swap 与页面回收
操作系统
磊 子2 天前
二.内核讲解
开发语言·操作系统·系统
下午写HelloWorld3 天前
Linux系统及Ubuntu常用指令
linux·ubuntu·操作系统
Surest3 天前
AI时代操作系统过时了么?
操作系统
小宇子2B3 天前
页表凭什么不撑爆内存,CPU 凭什么查得不嫌慢
操作系统
Surest3 天前
OpenHarmony 技术拆解(一):多内核兼容与硬件能力发布机制
操作系统
我命由我123453 天前
Windows 操作系统 - Windows 查看防火墙是否开启、Windows 查看防火墙放行端口
java·运维·开发语言·windows·java-ee·操作系统·运维开发