强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

D-Bus 完整教程 / 02 - D-Bus 架构详解

第 02 章:D-Bus 架构详解


2.1 整体架构

D-Bus 的架构可以分为四层:

┌─────────────────────────────────────────────────────┐
│              应用程序(使用 D-Bus 绑定库)              │  ← 第 4 层:应用层
├─────────────────────────────────────────────────────┤
│        D-Bus 绑定库(GLib / Qt / sd-bus / python)    │  ← 第 3 层:绑定层
├─────────────────────────────────────────────────────┤
│              D-Bus 守护进程 / Broker                  │  ← 第 2 层:路由层
│         (dbus-daemon / dbus-broker)                  │
├─────────────────────────────────────────────────────┤
│           Unix Domain Socket / TCP Socket            │  ← 第 1 层:传输层
└─────────────────────────────────────────────────────┘
层级组件职责
传输层Unix Socket / TCP原始字节传输
路由层dbus-daemon / dbus-broker消息路由、策略检查、服务激活
绑定层GLib、Qt、sd-bus、dbus-python提供高级语言 API
应用层用户程序定义接口、发送/接收消息

2.2 两种总线

2.2.1 System Bus(系统总线)

System Bus 是系统范围的总线,通常只有一个实例,以 root 或专门的 dbus 用户运行。

# 查看 System Bus 地址
echo $DBUS_SYSTEM_BUS_ADDRESS
# 通常为 unix:path=/var/run/dbus/system_bus_socket

# 查看进程
ps aux | grep 'dbus-daemon.*system'

特点

  • 需要 root 权限或策略允许才能连接
  • 承载系统级服务:systemdNetworkManagerudisks2bluetooth
  • 策略配置文件:/etc/dbus-1/system.d//usr/share/dbus-1/system.d/

2.2.2 Session Bus(会话总线)

Session Bus 是每个用户会话的总线,每个登录用户(甚至每个桌面会话)拥有独立的实例。

# 查看 Session Bus 地址
echo $DBUS_SESSION_BUS_ADDRESS
# 通常为 unix:path=/run/user/1000/bus

# 当 systemd 管理时
echo $DBUS_SESSION_BUS_ADDRESS
# unix:path=/run/user/1000/bus (由 systemd --user 管理)

特点

  • 任何用户进程都可连接(同一 UID 下)
  • 承载桌面服务:gnome-shelldolphinnotification-daemon
  • 用户注销后总线关闭

2.2.3 对比

维度System BusSession Bus
实例数全局唯一每用户会话一个
运行用户root / dbus当前登录用户
地址/var/run/dbus/system_bus_socket/run/user/<uid>/bus
策略文件/etc/dbus-1/system.d/通常不需要
典型服务systemd, NetworkManagergnome-shell, pipewire
生命周期随系统启动/关闭随用户会话

2.3 四种消息类型

D-Bus 协议定义了四种消息类型:

类型方向用途必须回复?
Method Call调用方 → 目标请求执行操作
Method Return目标 → 调用方返回结果
Error目标 → 调用方返回错误信息
Signal发送方 → 总线 → 订阅者广播事件

消息内部结构

每条 D-Bus 消息由 Header + Body 组成:

┌──────────────────────────────────────┐
│           Header Fields              │
│  ┌─────────────────────────────────┐ │
│  │ Message Type     (1 byte)       │ │
│  │ Flags            (1 byte)       │ │
│  │ Protocol Version (1 byte)       │ │
│  │ Body Length      (4 bytes)      │ │
│  │ Serial Number    (4 bytes)      │ │
│  │ Header Fields    (variable)     │ │
│  │   - PATH         (object path)  │ │
│  │   - INTERFACE    (string)       │ │
│  │   - MEMBER       (method/signal)│ │
│  │   - DESTINATION  (bus name)     │ │
│  │   - SENDER       (bus name)     │ │
│  │   - SIGNATURE    (type sig)     │ │
│  └─────────────────────────────────┘ │
├──────────────────────────────────────┤
│           Body (参数数据)              │
│  ┌─────────────────────────────────┐ │
│  │ arg0: int32                     │ │
│  │ arg1: string                    │ │
│  │ arg2: array of struct           │ │
│  └─────────────────────────────────┘ │
└──────────────────────────────────────┘

示例:捕获原始消息

# 使用 busctl monitor 查看原始消息流
busctl monitor --user

在另一个终端发送一条消息:

dbus-send --session --dest=org.freedesktop.DBus \
  --type=method_call --print-reply \
  /org/freedesktop/DBus \
  org.freedesktop.DBus.ListNames

busctl monitor 的输出:

‣ Type=method_call  Endian=l  Flags=0  Version=1
  Path=/org/freedesktop/DBus  Interface=org.freedesktop.DBus  Member=ListNames
  ARGS: (no args)

‣ Type=method_return  Endian=l  Flags=1  Version=1  ReplySerial=2
  ARGS: array [string "org.freedesktop.DBus", string ":1.42", ...]

2.4 D-Bus 地址格式

D-Bus 使用 地址字符串 来定位总线。地址格式为:

<transport>:<key1>=<value1>,<key2>=<value2>,...
传输类型地址示例说明
Unix Socket (path)unix:path=/var/run/dbus/system_bus_socket按文件路径连接
Unix Socket (abstract)unix:abstract=/tmp/dbus-XXXXXXLinux 抽象命名空间
TCPtcp:host=localhost,port=12345TCP 连接(跨机器)
systemdsystemd:由 systemd 传递的 socket
launchdlaunchd:env=DBUS_LAUNCHD_SESSION_BUS_SOCKETmacOS
# 查看 System Bus 地址
dbus-send --system --dest=org.freedesktop.DBus \
  --type=method_call --print-reply \
  /org/freedesktop/DBus \
  org.freedesktop.DBus.GetId

# 在配置文件中查看地址
cat /usr/share/dbus-1/system.conf | grep -A2 '<listen>'

2.5 匹配规则(Match Rules)

匹配规则用于控制信号的接收范围。客户端通过 org.freedesktop.DBus.AddMatch 方法向守护进程注册匹配规则。

语法

"type='signal',sender='org.example.Foo',interface='org.example.Bar',member='Baz',path='/com/example',arg0='hello'"

可用字段

字段说明示例
type消息类型signalmethod_call
sender发送方总线名称org.freedesktop.NetworkManager
interface接口名称org.freedesktop.DBus.Properties
member方法/信号名称StateChanged
path对象路径/org/freedesktop/NetworkManager
path_namespace路径前缀匹配/org/freedesktop
arg0 ~ arg63参数值匹配arg0='Connected'
arg0namespace参数为总线名称时按前缀匹配arg0namespace='org.freedesktop'
eavesdrop监听所有消息(需特权)eavesdrop='true'

实际操作

# 只接收 NetworkManager 的信号
dbus-send --session --dest=org.freedesktop.DBus \
  --type=method_call \
  /org/freedesktop/DBus \
  org.freedesktop.DBus.AddMatch \
  string:"type='signal',sender='org.freedesktop.NetworkManager'"

# 使用 busctl 设置匹配规则
busctl monitor --user \
  --match="type='signal',interface='org.freedesktop.DBus.Properties'"

# 删除匹配规则
dbus-send --session --dest=org.freedesktop.DBus \
  --type=method_call \
  /org/freedesktop/DBus \
  org.freedesktop.DBus.RemoveMatch \
  string:"type='signal',sender='org.freedesktop.NetworkManager'"

2.6 总线策略(Bus Policy)

策略定义了哪些进程可以连接总线、发送/接收哪些消息。配置文件位于:

目录说明
/etc/dbus-1/system.d/系统总线策略(系统管理员)
/usr/share/dbus-1/system.d/系统总线策略(包提供的默认)
/etc/dbus-1/session.d/会话总线策略(少见)
/usr/share/dbus-1/session.d/会话总线策略

策略文件示例

<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
  <!-- 只允许 root 用户拥有此名称 -->
  <policy user="root">
    <allow own="org.example.SystemService"/>
    <allow send_destination="org.example.SystemService"/>
  </policy>

  <!-- 默认策略:允许任何人调用此服务 -->
  <policy context="default">
    <allow send_destination="org.example.SystemService"
           send_interface="org.example.SystemService"/>
    <deny send_destination="org.example.SystemService"
          send_interface="org.example.SystemService.SecretMethod"/>
  </policy>
</busconfig>

策略标签

标签说明
<policy user="...">按用户匹配
<policy group="...">按组匹配
<policy context="default">默认策略
<allow ...>允许
<deny ...>拒绝

权限属性

属性说明
own允许拥有指定总线名称
send_destination允许发送到指定目标
send_interface限制到特定接口
send_member限制到特定方法/信号
send_type限制消息类型(method_call / signal)
receive_*控制接收权限

2.7 连接的生命周期

客户端                                    dbus-daemon
  │                                          │
  │──── TCP/Unix 连接 ──────────────────────→│
  │                                          │
  │──── AUTH EXTERNAL <uid-hex> ────────────→│  认证
  │←─── OK <guid> ──────────────────────────│
  │                                          │
  │──── BEGIN ──────────────────────────────→│  开始消息传输
  │                                          │
  │──── Hello (Method Call) ────────────────→│  获取唯一名称
  │←─── :1.42 (Method Return) ──────────────│
  │                                          │
  │──── RequestName("org.example.Foo") ────→│  请求公共名称
  │←─── DBUS_REQUEST_NAME_REPLY_PRIMARY ───│
  │                                          │
  │  ... 正常消息收发 ...                     │
  │                                          │
  │──── 连接关闭 ───────────────────────────→│  释放名称

注意Hello 方法是连接后调用的第一个方法,返回分配的唯一名称(如 :1.42)。在此之前不允许发送其他消息。


2.8 字节序与序列化

D-Bus 支持两种字节序:

标识字节序
l (0x6C)Little-endian(小端)
B (0x42)Big-endian(大端)

现代 Linux 系统上,几乎所有通信都使用 little-endian。

类型签名(Type Signature)

D-Bus 使用单字符编码的数据类型:

符号类型示例值
yBYTE0xFF
bBOOLEANtrue
nINT16-123
qUINT1665535
iINT32-100000
uUINT32100000
xINT64-9999999
tUINT649999999
dDOUBLE3.14
sSTRING“hello”
oOBJECT_PATH“/org/example”
vVARIANT任意类型
aARRAYas = string array
(...)STRUCT(si) = string + int32

组合示例:

  • as → 字符串数组
  • a{sv} → 键值字典(string → variant),极为常见
  • (si) → 结构体,包含字符串和 int32
  • a(si) → 结构体数组
# 发送复杂类型
dbus-send --session --dest=org.freedesktop.DBus \
  --type=method_call --print-reply \
  /org/freedesktop/DBus \
  org.freedesktop.DBus.ListNames

# 输出中可以看到类型信息

2.9 架构全景图

┌──────────────────────────────────────────────────────────────┐
│                        Linux System                          │
│                                                              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    │
│  │ systemd  │  │ Network  │  │ Bluez    │  │ udisks2  │    │
│  │          │  │ Manager  │  │          │  │          │    │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘    │
│       │              │              │              │          │
│  ═════╪══════════════╪══════════════╪══════════════╪════════  │
│       │         System Bus (/var/run/dbus/system_bus_socket) │
│  ═════╪══════════════╪══════════════╪══════════════╪════════  │
│       │              │              │              │          │
│  ┌────┴─────┐  ┌────┴─────┐  ┌────┴─────┐  ┌────┴─────┐    │
│  │ dbus-    │  │ Policy   │  │ Activation│  │ Monitoring│   │
│  │ daemon/  │  │ Engine   │  │ Engine   │  │ Engine   │    │
│  │ broker   │  └──────────┘  └──────────┘  └──────────┘    │
│  └──────────┘                                                │
│                                                              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                   │
│  │ GNOME    │  │ Nautilus │  │ Terminal │   ← Session Bus   │
│  │ Shell    │  │          │  │          │                   │
│  └──────────┘  └──────────┘  └──────────┘                   │
└──────────────────────────────────────────────────────────────┘

本章小结

概念说明
System Bus系统级服务通信,受策略保护
Session Bus用户会话级服务通信,自动随会话启停
四种消息Method Call、Method Return、Error、Signal
匹配规则控制信号接收范围的过滤表达式
总线策略XML 配置文件定义权限矩阵
类型签名D-Bus 数据类型的单字符编码

扩展阅读