9.1 KiB
9.1 KiB
锁屏信号未触发问题修复指南
问题描述
程序已成功连接到目标系统的 DBus 服务,但是系统锁屏时 onSessionLocked() 没有被调用。
此问题在 Ubuntu 和 Deepin 系统上都存在。
问题原因
1. Session 路径问题
原代码使用了固定路径 /org/freedesktop/login1/session/auto,但这个路径在大多数 Linux 系统上不起作用。需要使用实际的会话 ID 路径,例如:
/org/freedesktop/login1/session/c1/org/freedesktop/login1/session/2
2. 信号监听范围太窄
原代码只监听特定路径的信号,如果实际信号从其他路径发出,就无法接收到。
3. 缺少详细调试信息
无法判断到底是哪个环节出了问题:连接失败、信号未发出、还是信号发送者不匹配。
修复方案
主要改进
1. 动态获取 Session 路径
新增 getCurrentSessionPath() 方法,通过以下方式获取正确的会话路径:
QString ScreenLockDetector::getCurrentSessionPath()
{
// 方法1: 从环境变量获取
QString xdgSessionId = qgetenv("XDG_SESSION_ID");
if (!xdgSessionId.isEmpty()) {
return QString("/org/freedesktop/login1/session/%1").arg(xdgSessionId);
}
// 方法2: 通过 DBus 调用获取
QDBusInterface managerIface(
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
QDBusConnection::systemBus()
);
if (managerIface.isValid()) {
QDBusReply<QDBusObjectPath> reply =
managerIface.call("GetSessionByPID",
(quint32)QCoreApplication::applicationPid());
if (reply.isValid()) {
return reply.value().path();
}
}
return QString();
}
2. 双重信号连接策略
先尝试连接到特定会话路径,如果失败则连接到通用信号(空路径):
// 方法1: 连接到特定会话
QDBusConnection::systemBus().connect(
"org.freedesktop.login1",
sessionPath, // 具体路径
"org.freedesktop.login1.Session",
"Lock",
this,
SLOT(onSessionLocked())
);
// 方法2: 连接到所有会话(备用方案)
QDBusConnection::systemBus().connect(
"org.freedesktop.login1",
"", // 空路径 = 监听所有对象
"org.freedesktop.login1.Session",
"Lock",
this,
SLOT(onSessionLocked())
);
3. 增强的调试信息
- 继承
QDBusContext以获取信号发送者详细信息 - 在所有关键点添加详细日志输出
- 显示信号的 service、path、interface 和 member
void ScreenLockDetector::onSessionLocked()
{
qDebug() << "##################################################";
qDebug() << "## LOCK SIGNAL RECEIVED";
QDBusMessage msg = QDBusContext::message();
if (msg.type() != QDBusMessage::InvalidMessage) {
qDebug() << "## DBus Message Details:";
qDebug() << "## Service:" << msg.service();
qDebug() << "## Path:" << msg.path();
qDebug() << "## Interface:" << msg.interface();
qDebug() << "## Member:" << msg.member();
}
qDebug() << "##################################################";
setLockState(true);
}
4. 改进的状态查询
增强 queryCurrentLockState() 方法,正确读取 systemd-logind 的 LockedHint 属性:
QDBusMessage msg = QDBusMessage::createMethodCall(
"org.freedesktop.login1",
m_loginInterface->path(),
"org.freedesktop.DBus.Properties",
"Get"
);
msg << "org.freedesktop.login1.Session" << "LockedHint";
QDBusReply<QVariant> reply = QDBusConnection::systemBus().call(msg);
if (reply.isValid()) {
bool locked = reply.value().toBool();
setLockState(locked);
}
使用修复后的代码
1. 重新编译
./build.sh
2. 运行程序并观察日志
./run.sh
程序启动时会输出详细的连接信息:
=================================================
Initializing ScreenLockDetector...
=================================================
--- Connecting to Deepin DDE ---
Trying Deepin service: com.deepin.dde.lockFront
...
--- Connecting to GNOME ScreenSaver ---
GNOME ScreenSaver interface is valid
GNOME ActiveChanged signal connected: true
...
--- Connecting to Login Manager (systemd-logind) ---
Session path from XDG_SESSION_ID: /org/freedesktop/login1/session/c1
Current session path: /org/freedesktop/login1/session/c1
Login Manager interface is valid for session: /org/freedesktop/login1/session/c1
Session Lock signal connected: true
Session Unlock signal connected: true
...
3. 测试锁屏
锁定屏幕后,应该能看到:
##################################################
## LOCK SIGNAL RECEIVED
## Screen is now LOCKED
## DBus Message Details:
## Service: :1.43
## Path: /org/freedesktop/login1/session/c1
## Interface: org.freedesktop.login1.Session
## Member: Lock
##################################################
调试工具
工具 1: test_lock_signals.sh
这是一个全面的 DBus 信号监听脚本,用于诊断问题:
./test_lock_signals.sh
功能:
- 显示当前会话信息(XDG_SESSION_ID 等)
- 检查可用的锁屏服务
- 列出会话支持的所有信号
- 实时监听 session bus 和 system bus 的锁屏信号
- 保存日志供后续分析
使用方法:
- 运行脚本
- 按照提示锁定/解锁屏幕
- 观察输出的信号
- 按 Ctrl+C 停止
工具 2: debug_deepin_dbus.sh
专门用于 Deepin 系统的调试脚本:
./debug_deepin_dbus.sh
验证修复
检查列表
- 程序启动时显示"ScreenLockDetector initialized successfully"
- 至少有一个接口显示"connected: true"
- 显示了正确的 session 路径(不是 "auto")
- 锁屏时看到 "LOCK SIGNAL RECEIVED" 消息
- 解锁时看到 "UNLOCK SIGNAL RECEIVED" 消息
- 主窗口状态正确更新
如果仍然无法接收信号
-
运行 test_lock_signals.sh
./test_lock_signals.sh观察系统实际发出了什么信号
-
检查会话路径
echo $XDG_SESSION_ID loginctl show-session $XDG_SESSION_ID -
手动测试 DBus 连接
# 监听 system bus 的 Lock 信号 dbus-monitor --system "type='signal',interface='org.freedesktop.login1.Session',member='Lock'" # 在另一个终端锁屏 loginctl lock-session -
检查权限 确保用户有权限访问 system bus:
groups $USER用户应该在
sudo或wheel组中 -
对于 Deepin 系统
# 列出所有 Deepin 相关服务 dbus-send --session --print-reply --dest=org.freedesktop.DBus \ /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep deepin # 查看 lockFront 的接口 dbus-send --session --print-reply --dest=com.deepin.dde.lockFront \ /com/deepin/dde/lockFront org.freedesktop.DBus.Introspectable.Introspect
不同系统的特殊情况
Ubuntu / GNOME
- 主要通过
org.gnome.ScreenSaver的ActiveChanged信号 - 或通过 systemd-logind 的
Lock/Unlock信号
Deepin DDE
- 服务名可能是
com.deepin.dde.lockFront或org.deepin.dde.lockFront - 信号名可能是
Locked/Unlocked或Lock/Unlock - 需要通过 session bus 连接
KDE Plasma
- 使用
org.freedesktop.ScreenSaver - 也支持 systemd-logind
XFCE
- 主要依赖 systemd-logind
- 或
org.xfce.ScreenSaver
常见问题
Q: 为什么连接显示成功但没有收到信号?
A: 可能的原因:
- 连接到了错误的会话路径
- 桌面环境使用了不同的锁屏机制
- 信号签名不匹配(参数类型不对)
解决方法:使用 test_lock_signals.sh 查看实际信号。
Q: 在虚拟机中测试是否会有问题?
A: 可能会。某些虚拟机可能没有完整的 session 管理。建议:
- 确保虚拟机安装了完整的桌面环境
- 使用 GUI 登录而不是 SSH
- 检查
loginctl list-sessions是否显示你的会话
Q: Deepin 系统上还是不工作怎么办?
A: Deepin 不同版本的接口可能不同:
- 运行
debug_deepin_dbus.sh找到正确的服务名 - 修改
connectToDeepinDDE()中的服务列表 - 添加找到的服务配置
- 重新编译测试
技术参考
DBus 接口文档
- systemd-logind Session: https://www.freedesktop.org/wiki/Software/systemd/logind/
- GNOME ScreenSaver: https://wiki.gnome.org/Projects/GnomeScreensaver
Qt DBus 文档
- QDBusConnection: https://doc.qt.io/qt-5/qdbusconnection.html
- QDBusContext: https://doc.qt.io/qt-5/qdbuscontext.html
- QDBusInterface: https://doc.qt.io/qt-5/qdbusinterface.html
总结
修复的核心要点:
- ✅ 动态获取会话路径 - 不要硬编码 "auto"
- ✅ 多重连接策略 - 特定路径 + 通用监听
- ✅ 详细调试日志 - 便于诊断问题
- ✅ 正确读取属性 - 使用 Properties 接口
- ✅ 支持多种桌面环境 - Deepin/GNOME/KDE 等
这些修复应该能解决大多数 Linux 系统上的锁屏信号接收问题。