fix(backend_detect): use raw zbus for portal check to avoid OnceLock connection poisoning
ashpd caches zbus::Connection in a global OnceLock. When check_portal_available() created a Screencast proxy, the connection was cached there. When the function returned and its tokio Runtime dropped, the cached connection became dead. Subsequent setup_portal() calls reused this dead connection and hung forever. Fix: replace ashpd Screencast proxy with direct zbus D-Bus interface check, which does not touch the ashpd global connection cache. Add examples/test_portal.rs for minimal Portal ScreenCast testing.
This commit is contained in:
@@ -37,11 +37,10 @@ impl Dispatch<WlRegistry, GlobalListContents> for RegistryLs {
|
||||
}
|
||||
}
|
||||
|
||||
// 通过 D-Bus 检测 XDG Desktop Portal 的 ScreenCast 接口是否可用
|
||||
// 尝试创建 Screencast proxy,如果 Portal 服务未运行则返回 false
|
||||
// CAUTION: must NOT use ashpd here — ashpd caches zbus::Connection in a global
|
||||
// OnceLock; if the tokio runtime owning that connection is dropped before
|
||||
// setup_portal() runs, the cached connection becomes dead and hangs forever.
|
||||
fn check_portal_available() -> bool {
|
||||
use ashpd::desktop::screencast::Screencast;
|
||||
|
||||
let rt = match tokio::runtime::Runtime::new() {
|
||||
Ok(rt) => rt,
|
||||
Err(e) => {
|
||||
@@ -51,30 +50,43 @@ fn check_portal_available() -> bool {
|
||||
};
|
||||
|
||||
rt.block_on(async {
|
||||
let proxy = match Screencast::new().await {
|
||||
Ok(p) => p,
|
||||
let conn = match zbus::Connection::session().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
tracing::info!("Portal not available: {e}");
|
||||
tracing::info!("D-Bus session bus unavailable: {e}");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Verify the portal actually exposes ScreenCast capabilities,
|
||||
// not just that the D-Bus service is running.
|
||||
match proxy.available_source_types().await {
|
||||
Ok(types) if !types.is_empty() => {
|
||||
tracing::info!("Portal ScreenCast available (source types: {types:?})");
|
||||
let inner: zbus::Proxy = match zbus::proxy::Builder::new(&conn)
|
||||
.destination("org.freedesktop.portal.Desktop")
|
||||
.and_then(|b| b.path("/org/freedesktop/portal/desktop"))
|
||||
.and_then(|b| b.interface("org.freedesktop.portal.ScreenCast"))
|
||||
{
|
||||
Ok(b) => match b.build().await {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
tracing::info!("Portal ScreenCast interface not available: {e}");
|
||||
return false;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
tracing::info!("Portal ScreenCast proxy build failed: {e}");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
let version = match inner.get_property::<u32>("version").await {
|
||||
Ok(version) => {
|
||||
tracing::info!("Portal ScreenCast available (version: {version})");
|
||||
true
|
||||
}
|
||||
Ok(types) => {
|
||||
tracing::info!("Portal ScreenCast proxy exists but no source types available ({types:?})");
|
||||
false
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::info!("Portal ScreenCast available_source_types query failed: {e}");
|
||||
tracing::info!("Portal ScreenCast version query failed: {e}");
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
version
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user