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版本

流程图

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

步骤组件关键动作说明
应用 → SDKInitSoftBus(pkgName)应用初始化软总线,传入包名用于身份标识
SDK → SAM获取 SA Proxy (ID=4700)从 SystemAbilityManager 获取远程服务代理
SDK 自处理创建 SoftBusClientStub单例模式,用于接收服务端主动推送的消息
SDK → ServerSendRequest(REGISTER)通过 Binder 发起注册请求,携带 stub 引用和包名
ServerStubOnRemoteRequest()解析 Binder 协议码,分发到 memberFuncMap_
ServerStub权限检查校验调用方是否拥有 ohos.permission.DISTRIBUTED_DATA 等权限
SoftBusServerSoftbusRegisterService()业务层处理注册逻辑
SoftBusServer检查客户端是否已存在防止重复注册,若已存在则更新信息
SoftBusServer创建 DeathRecipient绑定死亡通知,客户端崩溃时服务端能感知并清理资源
ClientInfoManagerSoftbusAddService()持久化存储 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_SERVICESoftbusRegisterService框架
SERVER_CREATE_SESSION_SERVERCreateSessionServer传输
SERVER_OPEN_SESSIONOpenSession传输
SERVER_CLOSE_CHANNELCloseChannel传输
SERVER_SESSION_SENDMSGSendMessage传输
SERVER_JOIN_LNNJoinLNN组网
SERVER_LEAVE_LNNLeaveLNN组网
SERVER_PUBLISH_LNNPublishLNN发现
SERVER_REFRESH_LNNRefreshLNN发现
.........

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

Code接口功能域
CLIENT_ON_CHANNEL_OPENEDOnChannelOpened传输
CLIENT_ON_CHANNEL_MSGRECEIVEDOnChannelMsgReceived传输
CLIENT_ON_JOIN_RESULTOnJoinLNNResult组网
CLIENT_ON_NODE_ONLINE_STATE_CHANGEDOnNodeOnlineStateChanged组网
CLIENT_ON_REFRESH_DEVICE_FOUNDOnRefreshDeviceFound发现
.........

七、关键设计总结

设计要点说明
双向 IPCClient→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

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

更多推荐