tips:图片太大,如果图表看不清提供了高清图源

一、架构总览

分布式软总线在 standard 系统上采用 OHOS 标准的 IPC Binder 机制 实现 Client-Server 架构。整体结构如下:

二、Server 端详解

2.1 SA 注册与启动

SA Profile4700.json

{
    "process": "softbus_server",
    "systemability": [{
        "name": 4700,
        "libpath": "libsoftbus_server.z.so",
        "run-on-create": true,
        "distributed": false,
        "dump_level": 1
    }]
}
  • SA ID 为 4700,进程名为 softbus_server
  • run-on-create: true 表示 SystemAbilityManager 自动拉起
  • 由 init 配置 softbus_server.rc 在 post-fs-data 阶段启动

2.2 类继承体系(Server 端)

2.3 SoftBusServer — 业务实现层

softbus_server.h

关键点:

  • 双重继承class SoftBusServer : public SystemAbility, public SoftBusServerStub
  • OnStart() 中调用 InitSoftBusServer() 初始化所有核心模块
  • 每个接口方法的实现都是直接转发到 core/ 层的 C 函数
// 传输 → TransCreateSessionServer()
int32_t SoftBusServer::CreateSessionServer(const char *pkgName, const char *sessionName) {
    pid_t callingUid = OHOS::IPCSkeleton::GetCallingUid();
    pid_t callingPid = OHOS::IPCSkeleton::GetCallingPid();
    return TransCreateSessionServer(pkgName, sessionName, (int32_t)callingUid, (int32_t)callingPid);
}

// 组网 → LnnIpcServerJoin()
int32_t SoftBusServer::JoinLNN(const char *pkgName, void *addr, uint32_t addrTypeLen, bool isForceJoin) {
    pid_t callingPid = OHOS::IPCSkeleton::GetCallingPid();
    return LnnIpcServerJoin(pkgName, (int32_t)callingPid, addr, addrTypeLen, isForceJoin);
}

通过 IPCSkeleton::GetCallingUid/Pid() 获取调用方身份用于权限校验。

2.4 SoftBusServerStub — IPC 请求分发与权限

softbus_server_stub.h

核心机制是 函数映射表

// 构造函数中注册所有 IPC code → 处理函数 的映射
void SoftBusServerStub::InitMemberFuncMap() {
    memberFuncMap_[MANAGE_REGISTER_SERVICE]      = &SoftBusServerStub::SoftbusRegisterServiceInner;
    memberFuncMap_[SERVER_CREATE_SESSION_SERVER]  = &SoftBusServerStub::CreateSessionServerInner;
    memberFuncMap_[SERVER_OPEN_SESSION]           = &SoftBusServerStub::OpenSessionInner;
    memberFuncMap_[SERVER_JOIN_LNN]               = &SoftBusServerStub::JoinLNNInner;
    memberFuncMap_[SERVER_PUBLISH_LNN]            = &SoftBusServerStub::PublishLNNInner;
    // ... 40+ 个接口
}

// IPC 请求入口
int32_t SoftBusServerStub::OnRemoteRequest(uint32_t code, MessageParcel &data, 
                                            MessageParcel &reply, MessageOption &option) {
    // 1. 验证 InterfaceToken
    // 2. 权限检查 (AccessToken + memberPermissionMap_)
    // 3. 查 memberFuncMap_ 找到对应处理函数
    // 4. 反序列化 data → 调用虚函数(由 SoftBusServer 实现)→ 序列化 reply
}

权限映射

void SoftBusServerStub::InitMemberPermissionMap() {
    // 传输相关接口需要 DISTRIBUTED_DATASYNC 权限
    memberPermissionMap_[SERVER_CREATE_SESSION_SERVER] = OHOS_PERMISSION_DISTRIBUTED_DATASYNC;
    memberPermissionMap_[SERVER_OPEN_SESSION]          = OHOS_PERMISSION_DISTRIBUTED_DATASYNC;
    
    // 组网相关接口需要 DISTRIBUTED_SOFTBUS_CENTER 权限
    memberPermissionMap_[SERVER_JOIN_LNN]              = OHOS_PERMISSION_DISTRIBUTED_SOFTBUS_CENTER;
    memberPermissionMap_[SERVER_START_TIME_SYNC]        = OHOS_PERMISSION_DISTRIBUTED_SOFTBUS_CENTER;
    
    // SendMessage 无权限要求(通道已建立,消息发送本身不额外校验)
    memberPermissionMap_[SERVER_SESSION_SENDMSG]       = nullptr;
}

2.5 SoftbusClientInfoManager — 客户端注册管理

softbus_client_info_manager.h

Server 端维护一个 客户端信息表,记录所有已注册的客户端:

class SoftbusClientInfoManager {
    // key: pkgName, value: (pid, (IRemoteObject, DeathRecipient))
    std::unordered_multimap<std::string, ClientObjPair> clientObjectMap_;
    
    // 添加客户端(注册时调用)
    int32_t SoftbusAddService(const std::string &pkgName, const sptr<IRemoteObject> &object, ...);
    // 移除客户端(死亡时调用)
    int32_t SoftbusRemoveService(const sptr<IRemoteObject> &object, ...);
    // 获取客户端 Proxy(Server→Client 推送时使用)
    sptr<IRemoteObject> GetSoftbusClientProxy(const std::string &pkgName);
};

2.6 SoftBusDeathRecipient — 客户端死亡监听

softbus_server_death_recipient.h

当客户端进程异常死亡时,Binder 会触发 OnRemoteDied() 回调,Server 端执行清理:

  • 从 SoftbusClientInfoManager 移除该客户端
  • 调用 ClientDeathCallback() 清理该客户端关联的会话、通道等资源

2.7 服务端初始化流程

softbus_server_frame.c 中的 InitSoftBusServer()

InitSoftBusServer()
  ├─ SoftbusConfigInit()          // 读取特性配置
  ├─ LnnInitMonitorInit()         // 初始化监控
  ├─ ServerStubInit()             // IPC Stub 初始化
  ├─ SoftBusTimerInit()           // 定时器
  ├─ LooperInit()                 // 事件循环
  ├─ InitDdos()                   // DDOS 防护
  ├─ InitServicesAndModules()     // ★ 核心模块初始化
  │   ├─ ConnServerInit()         //   连接模块
  │   ├─ AuthInit()               //   认证模块
  │   ├─ DiscServerInit()         //   发现模块
  │   ├─ BusCenterServerInit()    //   组网模块
  │   ├─ TransServerInit()        //   传输模块
  │   ├─ DiscEventManagerInit()   //   发现事件管理
  │   ├─ WifiDirectManager::init()//   WiFi Direct
  │   ├─ ConnBleDirectInit()      //   BLE Direct
  │   └─ HiDumper + SysEvt       //   DFX
  └─ SoftBusBtInit()              // 蓝牙初始化

三、Client 端详解

3.1 类继承体系(Client 端)

3.2 ISoftBusClient — Server→Client 推送接口

if_softbus_client.h

这是 Server 主动推送给 Client 的回调接口,与 ISoftBusServer 方向相反:

接口方法 触发场景
OnChannelOpened() 通道打开成功
OnChannelOpenFailed() 通道打开失败
OnChannelClosed() 通道关闭
OnChannelMsgReceived() 收到通道消息
OnChannelQosEvent() QoS 事件
OnChannelLinkDown() 链路断开
OnJoinLNNResult() 组网结果回调
OnLeaveLNNResult() 退网结果回调
OnNodeOnlineStateChanged() 节点上下线
OnNodeBasicInfoChanged() 节点信息变化
OnTimeSyncResult() 时间同步结果
OnPublishLNNResult() 发布结果
OnRefreshLNNResult() 发现结果
OnRefreshDeviceFound() 发现设备
OnDataLevelChanged() 数据级别变化
OnBleRangeDone() BLE 测距完成

3.3 SoftBusClientStub — 客户端侧 IPC Stub

softbus_client_stub.h

与 Server Stub 结构对称,也是用 函数映射表 分发:

SoftBusClientStub::SoftBusClientStub() {
    memberFuncMap_[CLIENT_ON_CHANNEL_OPENED]          = &SoftBusClientStub::OnChannelOpenedInner;
    memberFuncMap_[CLIENT_ON_CHANNEL_MSGRECEIVED]     = &SoftBusClientStub::OnChannelMsgReceivedInner;
    memberFuncMap_[CLIENT_ON_JOIN_RESULT]             = &SoftBusClientStub::OnJoinLNNResultInner;
    memberFuncMap_[CLIENT_ON_NODE_ONLINE_STATE_CHANGED] = &SoftBusClientStub::OnNodeOnlineStateChangedInner;
    // ... 25+ 个回调
}

收到 Server 推送后,反序列化数据,调用 SDK 层的回调函数(如 TransOnChannelOpened()TransOnChannelMsgReceived()),最终触发应用注册的回调。

3.4 SoftBusServerProxyFrame — 客户端侧 IPC Proxy

softbus_server_proxy_standard.h

这是 Client 向 Server 发起请求的代理,核心流程:

int32_t SoftBusServerProxyFrame::SoftbusRegisterService(const char *clientPkgName, ...) {
    // 1. 获取 Server 端的 Remote 对象
    sptr<IRemoteObject> remote = Remote();
    
    // 2. 获取/创建 ClientStub(单例),作为 Server 回调的入口
    sptr<IRemoteObject> clientStub = SoftBusServerProxyFrame::GetRemoteInstance();
    
    // 3. 序列化请求
    MessageParcel data;
    data.WriteInterfaceToken(GetDescriptor());
    data.WriteRemoteObject(clientStub);      // ★ 把 ClientStub 传给 Server
    data.WriteCString(clientPkgName);
    
    // 4. 通过 Binder 发送 IPC 请求
    MessageParcel reply;
    MessageOption option;
    int32_t err = remote->SendRequest(MANAGE_REGISTER_SERVICE, data, reply, option);
    
    // 5. 读取返回值
    return reply.ReadInt32(serverRet);
}

关键点GetRemoteInstance() 使用双重检查锁创建 SoftBusClientStub 单例,注册时将其作为 IRemoteObject 传给 Server,这样 Server 就有了向 Client 推送的通道。


四、双向 IPC 通信模型

这是整个架构最核心的设计——双向 IPC

① 请求方向(Client → Server)

  • 应用调用公开 API → SDK 层 → SoftBusServerProxyFrame 序列化参数 → Binder SendRequest() → Server 端 SoftBusServerStub::OnRemoteRequest() 反序列化 → 权限检查 → 调用 SoftBusServer 的虚函数实现 → 转发到 core/ 层 C 函数

② 推送方向(Server → Client)

  • Server 端核心模块产生事件 → 通过 SoftbusClientInfoManager::GetSoftbusClientProxy() 获取客户端 Proxy → 调用 Proxy 的 SendRequest() → Binder → Client 端 SoftBusClientStub::OnRemoteRequest() 反序列化 → 调用 SDK 回调 → 触发应用层回调

五、客户端注册流程(完整时序)

Mermid版本

流程图

关键流程说明(配合图表理解)

步骤 组件 关键动作 说明
应用 → SDK InitSoftBus(pkgName) 应用初始化软总线,传入包名用于身份标识
SDK → SAM 获取 SA Proxy (ID=4700) 从 SystemAbilityManager 获取远程服务代理
SDK 自处理 创建 SoftBusClientStub 单例模式,用于接收服务端主动推送的消息
SDK → Server SendRequest(REGISTER) 通过 Binder 发起注册请求,携带 stub 引用和包名
ServerStub OnRemoteRequest() 解析 Binder 协议码,分发到 memberFuncMap_
ServerStub 权限检查 校验调用方是否拥有 ohos.permission.DISTRIBUTED_DATA 等权限
SoftBusServer SoftbusRegisterService() 业务层处理注册逻辑
SoftBusServer 检查客户端是否已存在 防止重复注册,若已存在则更新信息
SoftBusServer 创建 DeathRecipient 绑定死亡通知,客户端崩溃时服务端能感知并清理资源
ClientInfoManager SoftbusAddService() 持久化存储 clientProxypkgNamepid/uid 映射关系

注册完成后:

  • Server 端持有 Client 的 IRemoteObject(即 SoftBusClientStub),可以随时向 Client 推送事件
  • Client 端持有 Server 的 IRemoteObject(即 SA Proxy),可以随时向 Server 发起请求
  • DeathRecipient 确保 Client 异常死亡时 Server 能感知并清理资源

六、IPC 接口码定义

所有 IPC 通信的 code 定义在 softbus_server_ipc_interface_code.h 中,分为两组:

Server 端接口码(Client → Server 请求)

Code 接口 功能域
MANAGE_REGISTER_SERVICE SoftbusRegisterService 框架
SERVER_CREATE_SESSION_SERVER CreateSessionServer 传输
SERVER_OPEN_SESSION OpenSession 传输
SERVER_CLOSE_CHANNEL CloseChannel 传输
SERVER_SESSION_SENDMSG SendMessage 传输
SERVER_JOIN_LNN JoinLNN 组网
SERVER_LEAVE_LNN LeaveLNN 组网
SERVER_PUBLISH_LNN PublishLNN 发现
SERVER_REFRESH_LNN RefreshLNN 发现
... ... ...

Client 端接口码(Server → Client 推送)

Code 接口 功能域
CLIENT_ON_CHANNEL_OPENED OnChannelOpened 传输
CLIENT_ON_CHANNEL_MSGRECEIVED OnChannelMsgReceived 传输
CLIENT_ON_JOIN_RESULT OnJoinLNNResult 组网
CLIENT_ON_NODE_ONLINE_STATE_CHANGED OnNodeOnlineStateChanged 组网
CLIENT_ON_REFRESH_DEVICE_FOUND OnRefreshDeviceFound 发现
... ... ...

七、关键设计总结

设计要点 说明
双向 IPC Client→Server 请求 + Server→Client 推送,两条 Binder 通道
SA 机制 Server 以 SystemAbility (ID=4700) 运行在独立进程,系统自动拉起
Stub-Proxy 分离 Server Stub 做反序列化+权限;Client Stub 做反序列化+回调分发
函数映射表 memberFuncMap_ 将 IPC code 映射到成员函数指针,避免巨大 switch-case
权限双检 AccessToken 框架检查 + memberPermissionMap_ 接口级权限映射
DeathRecipient 双向死亡监听,Client 死亡 → Server 清理;Server 死亡 → Client 重连
客户端管理 SoftbusClientInfoManager 以 pkgName+pid 为键管理多客户端
PID/UID 传递 通过 IPCSkeleton::GetCallingPid/Uid() 获取调用方身份
模块化初始化 InitSoftBusServer() 按依赖顺序初始化 Conn→Auth→Disc→BusCenter→Trans
Logo

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

更多推荐