使用zbus从DBus接收UPower设备属性变更信号
监听UPower设备属性变化(zbus新版本适配方案)
问题说明
终端通过以下命令可正常监听电池设备的属性变化:
$ dbus-monitor --system "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/org/freedesktop/UPower/devices/battery_BAT0'"
但使用zbus新版本重构代码时,原基于zbus 1.8的方案失效,尝试MatchRule结合DBusProxy::receive_all_signals()的方式无法正常捕获信号。
新版本zbus正确实现
以下两种方案均可实现需求,推荐第二种更简洁的方式:
方案一:手动匹配规则+连接监听信号
直接通过DBus连接添加匹配规则,然后监听所有符合规则的信号:
use zbus::{Connection, MessageType, MatchRule}; use zbus::zvariant::Dict; #[tokio::main] async fn main() -> zbus::Result<()> { // 建立系统总线连接 let connection = Connection::system().await?; let battery_path = "/org/freedesktop/UPower/devices/battery_BAT0"; // 构建与dbus-monitor完全一致的匹配规则 let match_rule = MatchRule::builder() .msg_type(MessageType::Signal) .path(battery_path)? .interface("org.freedesktop.DBus.Properties")? .member("PropertiesChanged")? .build(); // 向DBus总线注册匹配规则 connection.add_match_rule(match_rule).await?; // 监听信号流并处理 let mut signal_stream = connection.receive_signals().await?; while let Some(signal) = signal_stream.next().await { let msg = signal.message(); // 解析PropertiesChanged信号的参数 let (interface, changed_props, invalidated): (String, Dict, Vec<String>) = msg.body()?; println!("接口: {}", interface); println!("变化的属性: {:?}", changed_props); println!("失效的属性: {:?}", invalidated); } Ok(()) }
方案二:使用PropertiesProxy自动监听
利用zbus提供的PropertiesProxy直接监听属性变化,无需手动构建匹配规则:
use zbus::fdo::PropertiesProxy; #[tokio::main] async fn main() -> zbus::Result<()> { let connection = Connection::system().await?; let battery_path = "/org/freedesktop/UPower/devices/battery_BAT0"; // 构建Properties代理,指定目标对象路径和服务名 let props_proxy = PropertiesProxy::builder(&connection) .path(battery_path)? .destination("org.freedesktop.UPower")? .build() .await?; // 获取PropertiesChanged信号的监听流 let mut props_stream = props_proxy.receive_properties_changed().await?; while let Some(signal) = props_stream.next().await { let args = signal.args()?; println!("接口名: {}", args.interface_name); println!("变化属性: {:?}", args.changed_properties); println!("失效属性: {:?}", args.invalidated_properties); } Ok(()) }
原代码失效原因
- 旧版本
DBusProxy::next_signal()本质是直接从连接中拉取所有信号,而新版本proxy.receive_all_signals()仅监听org.freedesktop.DBus接口自身的信号(如NameOwnerChanged),并非目标UPower设备的属性变化信号。 - 正确的做法是直接通过
Connection监听全局信号,或使用对应对象的PropertiesProxy来绑定特定对象的属性变化信号。
依赖配置
确保Cargo.toml中使用最新版zbus及异步运行时:
[dependencies] zbus = "4.0" tokio = { version = "1.0", features = ["full"] }
内容的提问来源于stack exchange,提问作者Flowneee
相关产品推荐
相关产品推荐

