分布式软总线核心代码分析(三)

发布时间:2026/6/27 20:39:17
分布式软总线核心代码分析(三) 组网前言前面分析了从设备发布到设备发现的业务流程设备发现会触发软总线业务链路的第三步---组网发布服务 ──→ 发现服务 ──→ 组网 ──→ 传输 (Publish) (Discover) (Join) (Transmit)发现服务到组网的衔接点Discovery 层发现设备 │ ▼ DiscOnDeviceFound(device) ← disc_manager.c:406 │ 匹配 capability → 通知订阅者 │ ▼ LNN Discovery Manager │ DeviceFound(addr, infoReport) ← lnn_discovery_manager.c:63 │ → LnnNotifyDiscoveryDevice(addr, infoReport, true) -触发组网的桥梁 │ ▼ Net Builder (组网模块) │ LnnNotifyDiscoveryDevice() ← lnn_net_builder.c:1128 │ → 创建 JoinLnnMsgPara │ → PostBuildMessageToHandler(MSG_TYPE_DISCOVERY_DEVICE) │ ▼ TrySendJoinLNNRequest() ← lnn_net_builder.c:237 │ → FindConnectionFsmByAddr() 查找/创建连接状态机 │ → PostJoinRequestToConnFsm() 发起认证连接 │ ▼ LnnConnectionFsm (连接状态机) │ → AuthStartVerify() 认证 │ → 认证成功 → 设备上线 │ ▼ LnnNotifyOnlineState() ← bus_center_event.c │ → 通知所有注册了 EVENT_NODE_STATE_ONLINE 的模块 │ ▼ 传输层可用组网模块的核心文件文件职责lnn_net_builder.c组网主逻辑发现设备→发起连接→认证lnn_net_builder_process.c消息处理处理 MSG_TYPE_DISCOVERY_DEVICE 等消息lnn_connection_fsm.c连接状态机管理连接的完整生命周期lnn_connection_fsm_process.c状态机状态转换处理lnn_sync_info_manager.c设备信息同步lnn_topo_manager.c网络拓扑管理DiscManager 发现设备后LNN 层注册的回调g_discCb.OnDeviceFound被调用经过两层DeviceFound函数中转最终到达LnnNotifyDiscoveryDevice发现服务是组网的前提再次声明在5.1版本中不存在startdiscovery这种函数见我之前的文章manager给系统的接口没有startdiscovery不信谣不传谣。LnnNotifyDiscoveryDevice函数签名int32_t LnnNotifyDiscoveryDevice( const ConnectionAddr *addr, // 发现设备的连接地址IP端口 / BLE MAC const LnnDfxDeviceInfoReport *infoReport, // 设备诊断信息设备类型等 bool isNeedConnect) // 是否需要发起连接true主动组网false仅记录逐行解读int32_t LnnNotifyDiscoveryDevice(...) { // 1. 地址校验 if (LnnIsConnectionAddrInvalid(addr)) { return SOFTBUS_INVALID_PARAM; } // 2. 模块初始化检查 if (g_netBuilder.isInit false) { return SOFTBUS_NO_INIT; } // 3. 诊断信息校验 if (infoReport NULL) { return SOFTBUS_INVALID_PARAM; } // 4. 构造消息参数 para CreateJoinLnnMsgPara(addr, infoReport, DEFAULT_PKG_NAME, isNeedConnect, false); // 填充内容: // para-pkgName com.huawei.nearby (默认包名) // para-isNeedConnect isNeedConnect (是否需要连接) // para-isForceJoin false (不强制加入) // para-addr 设备地址 // para-infoReport 诊断信息 // 5. 投递异步消息到组网线程 PostBuildMessageToHandler(MSG_TYPE_DISCOVERY_DEVICE, para); // 消息类型: MSG_TYPE_DISCOVERY_DEVICE // 处理函数: ProcessDevDiscoveryRequest() }para结构体typedef struct { char pkgName[PKG_NAME_SIZE_MAX]; bool isNeedConnect; bool isSession; bool isForceJoin; ConnectionAddr addr; NodeInfo *dupInfo; LnnDfxDeviceInfoReport infoReport; } JoinLnnMsgPara;函数功能LnnNotifyDiscoveryDevice是发现服务到组网流程的桥梁函数它将发现的设备地址封装为异步消息投递到组网线程由组网线程的ProcessDevDiscoveryRequest接手真正开始组网。这个函数不做任何组网操作只做一件事构造消息参数投递到组网线程的消息队列。LnnNotifyDiscoveryDevice() ← 调用方线程可能是介质回调线程 │ │ 构造 JoinLnnMsgPara │ PostBuildMessageToHandler(MSG_TYPE_DISCOVERY_DEVICE, para) │ ▼ 组网线程消息队列 │ ... │ MSG_TYPE_DISCOVERY_DEVICE para │ ... ▼ NetBuilderMessageHandler() ← 组网线程取出消息 │ g_messageProcessor[MSG_TYPE_DISCOVERY_DEVICE] ▼ ProcessDevDiscoveryRequest() ← lnn_net_builder_process.c:259 │ TrySendJoinLNNRequest(para, false, false) ▼ 真正的组网逻辑开始...为什么用异步消息LnnNotifyDiscoveryDevice可能被介质回调线程调用而组网涉及认证、状态机等耗时操作不能在回调线程中阻塞执行所以通过消息队列投递到组网线程异步处理。void NetBuilderMessageHandler(SoftBusMessage *msg)连接机制PostBuildMessageToHandler() ← lnn_net_builder.c:127 │ │ 1. CreateNetBuilderMessage(msgType, para) ← lnn_net_builder.c:113 │ 创建 SoftBusMessage: │ msg-what msgType (如 MSG_TYPE_DISCOVERY_DEVICE) │ msg-obj para │ msg-handler g_netBuilder.handler ← 关键: 绑定了 handler │ │ 2. g_netBuilder.looper-PostMessage(looper, msg) │ 将消息投递到 Looper 消息队列 │ ▼ Looper 线程取出消息 │ 根据 msg-handler 找到 g_netBuilder.handler │ 调用 handler.HandleMessage(msg) │ ▼ NetBuilderMessageHandler(msg) ← lnn_net_builder_process.c:825 │ │ g_messageProcessor[msg-what](msg-obj) │ ▼ 对应的处理函数函数注册绑定位置static int32_t InitNetBuilderLooper(void) { ... LnnGetNetBuilder()-looper GetLooper(LOOP_TYPE_DEFAULT); // 获取默认 Looper LnnGetNetBuilder()-handler.name NetBuilderHandler; LnnGetNetBuilder()-handler.looper LnnGetNetBuilder()-looper; LnnGetNetBuilder()-handler.HandleMessage NetBuilderMessageHandler; // ← 绑定在这里 ... }函数功能核心代码就最后一行按照消息类型查表调用对应的函数。消息分发表下标消息类型处理函数业务含义0MSG_TYPE_JOIN_LNNProcessJoinLNNRequest主动加入网络1MSG_TYPE_DISCOVERY_DEVICEProcessDevDiscoveryRequest发现设备→触发组网2MSG_TYPE_CLEAN_CONN_FSMProcessCleanConnectionFsm清理连接状态机3MSG_TYPE_VERIFY_RESULTProcessVerifyResult认证结果处理4MSG_TYPE_DEVICE_VERIFY_PASSProcessDeviceVerifyPass设备认证通过5MSG_TYPE_DEVICE_DISCONNECTProcessDeviceDisconnect设备断连6MSG_TYPE_DEVICE_NOT_TRUSTEDProcessDeviceNotTrusted设备不可信7MSG_TYPE_LEAVE_LNNProcessLeaveLNNRequest主动离开网络8MSG_TYPE_SYNC_OFFLINE_FINISHProcessSyncOfflineFinish离线同步完成9MSG_TYPE_NODE_STATE_CHANGEDProcessNodeStateChanged节点状态变化10MSG_TYPE_MASTER_ELECTProcessMasterElect主节点选举11MSG_TYPE_LEAVE_INVALID_CONNProcessLeaveInvalidConn离开无效连接12MSG_TYPE_LEAVE_BY_ADDR_TYPEProcessLeaveByAddrType按地址类型离开13MSG_TYPE_LEAVE_SPECIFICProcessLeaveSpecific离开指定连接14MSG_TYPE_LEAVE_BY_AUTH_IDProcessLeaveByAuthId按认证ID离开15MSG_TYPE_RE_SYNC_DEVICE_NAMEProcessSetReSyncDeviceName重新同步设备名按业务阶段分类入网阶段 (加入): MSG_TYPE_JOIN_LNN → ProcessJoinLNNRequest MSG_TYPE_DISCOVERY_DEVICE → ProcessDevDiscoveryRequest MSG_TYPE_VERIFY_RESULT → ProcessVerifyResult MSG_TYPE_DEVICE_VERIFY_PASS→ ProcessDeviceVerifyPass 在线阶段 (维护): MSG_TYPE_NODE_STATE_CHANGED→ ProcessNodeStateChanged MSG_TYPE_MASTER_ELECT → ProcessMasterElect MSG_TYPE_RE_SYNC_DEVICE_NAME → ProcessSetReSyncDeviceName MSG_TYPE_SYNC_OFFLINE_FINISH → ProcessSyncOfflineFinish 离网阶段 (离开): MSG_TYPE_LEAVE_LNN → ProcessLeaveLNNRequest MSG_TYPE_DEVICE_DISCONNECT → ProcessDeviceDisconnect MSG_TYPE_DEVICE_NOT_TRUSTED→ ProcessDeviceNotTrusted MSG_TYPE_LEAVE_INVALID_CONN→ ProcessLeaveInvalidConn MSG_TYPE_LEAVE_BY_ADDR_TYPE→ ProcessLeaveByAddrType MSG_TYPE_LEAVE_SPECIFIC → ProcessLeaveSpecific MSG_TYPE_LEAVE_BY_AUTH_ID → ProcessLeaveByAuthId 清理阶段: MSG_TYPE_CLEAN_CONN_FSM → ProcessCleanConnectionFsm组网核心函数链ProcessDevDiscoveryRequest(para) ← lnn_net_builder_process.c:256 │ 只有一行: 转发 ▼ TrySendJoinLNNRequest(para, false, false) ← lnn_net_builder.c:237 │ │ ★ 这是组网的核心分发函数决定走哪条路径 │ ├─ 路径1: 没有已有连接 → 创建新连接状态机 ├─ 路径2: 已有连接且在线 → 可能重新认证 ├─ 路径3: 并发数已满 → 挂起等待 └─ 路径4: WiFi 账号变更 → 重新认证代码分析int32_t TrySendJoinLNNRequest(const JoinLnnMsgPara *para, bool needReportFailure, bool isShort) { // 1. 根据是否需要连接决定 isShort // isNeedConnecttrue → isShortfalse (长连接需要组网) // isNeedConnectfalse → isShorttrue (短连接仅记录) isShort para-isNeedConnect ? false : true; // 2. 查找是否已有该地址的连接状态机 LnnConnectionFsm *connFsm FindConnectionFsmByAddr(para-addr, isShort); // 3. 三种分支分支一没有已有连接/分支已死/设备信息变更if (connFsm NULL || connFsm-isDead || CheckRemoteBasicInfoChanged(para-dupInfo)) { // 3a. 并发数已满→ 挂起等待 if (TryPendingJoinRequest(para, needReportFailure)) { return SOFTBUS_OK; // 等待后续处理 } // 3b. 创建新连接状态机 或 复用已死的连接 ret PostJoinRequestToConnFsm(connFsm, para, needReportFailure); return ret; }分支1 │ ├─ TryPendingJoinRequest() 返回 true │ → 当前并发连接数已达上限 │ → 将请求挂入 g_netBuilder.pendingList 等待队列 │ → 等某个连接完成上线或失败后再取出执行 │ → 直接返回不创建新状态机 │ └─ TryPendingJoinRequest() 返回 false → 并发数未满可以立即处理 → PostJoinRequestToConnFsm(connFsm, para, needReportFailure) → 创建新的连接状态机 或 复用已死的状态机 → 启动状态机进入 AUTH 认证状态PostJoinRequestToConnFsm函数功能创建或复用连接状态机并向它发送 JOIN_REQUEST 消息正式启动组网1.查找状态机状态再检查一次有没有关联可用的状态机if (connFsm NULL) { connFsm FindConnectionFsmByAddr(para-addr, false); }2.判定条件满足创建新的状态机connFsm NULL || connFsm-isDead || 设备信息变更? → StartNewConnectionFsm(¶-addr, pkgName, isNeedConnect) ★ 这是创建连接状态机的核心函数 ★ 创建后状态机处于初始状态等待 START 消息 → 复制设备信息: connFsm-connInfo.dupInfo DupNodeInfo(para-dupInfo) → isCreate true ← 标记本次是新创建的if (connFsm NULL || connFsm-isDead || CheckRemoteBasicInfoChanged(para-dupInfo)) { connFsm StartNewConnectionFsm(para-addr, para-pkgName, para-isNeedConnect); if (connFsm ! NULL) { connFsm-connInfo.dupInfo (para-dupInfo NULL) ? NULL : DupNodeInfo(para-dupInfo); } isCreate true; }3.标记会话类型para-isSession? → connFsm-isSession true4.发送 JOIN_REQUEST 到状态机if (connFsm NULL || LnnSendJoinRequestToConnFsm(connFsm, false) ! SOFTBUS_OK)LnnSendJoinRequestToConnFsm(connFsm, false) → 向状态机投递 FSM_CTRL_MSG_START 消息 → 状态机收到后进入 AUTH 认证状态4.1发送JOIN_REQUEST 失败发送失败? → needReportFailure? → LnnNotifyJoinResult() 通知上层组网失败 → isCreate? → 销毁刚创建的状态机回滚if (needReportFailure) { LnnNotifyJoinResult((ConnectionAddr *)para-addr, NULL, SOFTBUS_NETWORK_JOIN_REQUEST_ERR); NotifyStateForSession(para-addr); } if (connFsm ! NULL isCreate) { LnnFsmRemoveMessageByType(connFsm-fsm, FSM_CTRL_MSG_START); ListDelete(connFsm-node); --LnnGetNetBuilder()-connCount; LnnDestroyConnectionFsm(connFsm); } rc SOFTBUS_NETWORK_JOIN_REQUEST_ERR;4.2 发送JOIN_REQUEST成功记录诊断信息 设置连接标志 → JOIN_REQUEST: 用户主动发起的组网 → JOIN_AUTO: 自动触发的组网如发现服务触发if (rc SOFTBUS_OK) { connFsm-connInfo.infoReport para-infoReport; connFsm-connInfo.flag | (needReportFailure ? LNN_CONN_INFO_FLAG_JOIN_REQUEST : LNN_CONN_INFO_FLAG_JOIN_AUTO); LNN_LOGI(LNN_BUILDER, infoReport.osType%{public}d, infoReport.type%{public}X, connFsm-connInfo.infoReport.osType, connFsm-connInfo.infoReport.type); }核心流程图PostJoinRequestToConnFsm(connFsm, para, needReportFailure) │ ├─ connFsm 为空? → 再查一次 │ ├─ 仍为空/已死/信息变更? │ │ │ ▼ │ StartNewConnectionFsm() ← 创建新连接状态机 │ │ │ │ 内部做了: │ │ ├─ LnnCreateConnectionFsm() 分配内存初始化状态机 │ │ ├─ 设置4个状态的处理函数 │ │ │ AUTH → AuthStateProcess │ │ │ CLEAN_INVALID_CONN → CleanInvalidConnStateProcess │ │ │ ONLINE → OnlineStateProcess │ │ │ LEAVING → LeavingStateProcess │ │ ├─ ListAdd(g_netBuilder.fsmList) 加入全局状态机链表 │ │ └─ LnnFsmStart() 启动状态机线程 │ │ │ ▼ │ connFsm 已创建处于初始状态等待消息 │ ▼ LnnSendJoinRequestToConnFsm(connFsm, false) │ │ 向状态机投递 FSM_CTRL_MSG_START 消息 │ ▼ 状态机线程收到消息 -状态机部分 │ ▼ AuthStateProcess() ← 进入认证状态发起认证 │ ▼ AuthStartVerify() ← 真正开始认证分支二已有连接且在线if ((connFsm-connInfo.flag LNN_CONN_INFO_FLAG_ONLINE) ! 0) { // WiFi 连接 → 刷新认证信息 if (connFsm-connInfo.addr.type CONNECTION_ADDR_WLAN || ...) { AuthFlushDevice(uuid); } // 发送 JOIN_REQUEST 到状态机可能触发重新同步 LnnSendJoinRequestToConnFsm(connFsm, para-isForceJoin); }WiFi/以太网连接情况下WiFi 连接的设备可能因为网络切换、密钥更新等原因导致认证信息过期需要刷新确保后续通信正常。BLE/USB 连接不需要此操作。if (connFsm-connInfo.addr.type CONNECTION_ADDR_WLAN || connFsm-connInfo.addr.type CONNECTION_ADDR_ETH) { char uuid[UUID_BUF_LEN] {0}; (void)LnnConvertDlId(connFsm-connInfo.peerNetworkId, CATEGORY_NETWORK_ID, CATEGORY_UUID, uuid, UUID_BUF_LEN); (void)AuthFlushDevice(uuid); }步骤说明LnnConvertDlId将 peerNetworkId 转换为 UUIDAuthFlushDevice用 UUID 刷新认证设备的密钥/会话信息向状态机发送 JOIN_REQUESTif ((LnnSendJoinRequestToConnFsm(connFsm, para-isForceJoin) ! SOFTBUS_OK) needReportFailure) { LNN_LOGE(LNN_BUILDER, online status, process join lnn request failed); LnnNotifyJoinResult((ConnectionAddr *)para-addr, NULL, SOFTBUS_NETWORK_JOIN_REQUEST_ERR); }设备已在线但仍然发送 JOIN_REQUEST可能触发重新同步设备信息设备名、能力等可能已变化强制重连isForceJointrue时失败时通知上层组网结果。通知会话层如果这次发现请求来自会话层isSessiontrue直接通知会话层该设备已就绪因为设备已在线不需要再等认证。if (para-isSession para-dupInfo ! NULL) { LnnNotifyStateForSession(para-dupInfo-deviceInfo.deviceUdid, SOFTBUS_OK); }场景总结设备A 和 设备B 已经组网在线 │ │ 设备A 再次发现 设备B 的广播 │ (可能是周期性广播、或能力变更广播) ▼ TrySendJoinLNNRequest 进入分支2 │ ├─ WiFi连接 → AuthFlushDevice() 刷新认证信息 ├─ 发送 JOIN_REQUEST 触发信息重新同步 └─ 会话请求 → 通知会话层就绪 跳过认证直接可用分支三WiFi 账号变更 → 重新认证if (addr.type CONNECTION_ADDR_WLAN IsNeedWifiReauth(connFsm-connInfo.peerNetworkId, addr.peerUid, ...)) { // 直接发起重新认证 AuthStartVerify(authConn, requestId, LnnGetReAuthVerifyCallback(), ...); }ConnectionAddr addr para-addr;拷贝地址的值后面para要释放if (addr.type ! CONNECTION_ADDR_WLAN || !IsNeedWifiReauth(connFsm-connInfo.peerNetworkId, addr.peerUid, MAX_ACCOUNT_HASH_LEN)) { LNN_LOGI(LNN_BUILDER, account not change no need reauth); FreeJoinLnnMsgPara(para); return SOFTBUS_OK; }退出条件条件含义addr.type ! CONNECTION_ADDR_WLAN非 WiFi 连接不存在账号变更问题直接返回!IsNeedWifiReauth(...)WiFi 连接但账号未变更不需要重新认证直接返回为什么只有 WiFi 需要重新认证WiFi 连接依赖账号体系如华为账号账号切换意味着信任关系可能变化需要重新认证。BLE/USB 连接不依赖账号无需此处理。重新认证AuthConnInfo authConn; uint32_t requestId AuthGenRequestId(); LnnConvertAddrToAuthConnInfo(addr, authConn); DfxRecordLnnAuthStart(authConn, para, requestId); FreeJoinLnnMsgPara(para); return AuthStartVerify(authConn, requestId, LnnGetReAuthVerifyCallback(), AUTH_MODULE_LNN, false);步骤说明AuthGenRequestId()生成认证请求 IDLnnConvertAddrToAuthConnInfo将 ConnectionAddr 转换为认证层需要的 AuthConnInfoDfxRecordLnnAuthStart记录诊断信息FreeJoinLnnMsgPara释放参数之后不再使用AuthStartVerify发起重新认证注意回调是LnnGetReAuthVerifyCallback三个分支完整对比TrySendJoinLNNRequest │ ├─ 分支1: 无已有连接 │ → 创建新连接状态机 → 进入 AUTH 状态 → 认证 │ 场景: 首次发现设备 │ ├─ 分支2: 已在线 │ → 刷新认证 重新同步 通知会话层 │ 场景: 设备已组网再次收到广播 │ └─ 分支3: WiFi 账号变更 → AuthStartVerify() 重新认证 场景: 同一设备但登录账号变了信任关系需要重新建立分支三与分支一区别对比分支1新连接分支3重新认证认证方式通过状态机AuthStateProcess发起直接调用AuthStartVerify回调LnnGetVerifyCallbackLnnGetReAuthVerifyCallback状态机创建新的走完整流程复用已有的只做认证组网状态机部分暂时保留