ScreenLockDetector/LOCK_SIGNAL_FIX.md

331 lines
9.1 KiB
Markdown
Raw Normal View History

# 锁屏信号未触发问题修复指南
## 问题描述
程序已成功连接到目标系统的 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()` 方法,通过以下方式获取正确的会话路径:
```cpp
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. 双重信号连接策略
先尝试连接到特定会话路径,如果失败则连接到通用信号(空路径):
```cpp
// 方法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
```cpp
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` 属性:
```cpp
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. 重新编译
```bash
./build.sh
```
### 2. 运行程序并观察日志
```bash
./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 信号监听脚本,用于诊断问题:
```bash
./test_lock_signals.sh
```
功能:
1. 显示当前会话信息XDG_SESSION_ID 等)
2. 检查可用的锁屏服务
3. 列出会话支持的所有信号
4. 实时监听 session bus 和 system bus 的锁屏信号
5. 保存日志供后续分析
使用方法:
1. 运行脚本
2. 按照提示锁定/解锁屏幕
3. 观察输出的信号
4. 按 Ctrl+C 停止
### 工具 2: debug_deepin_dbus.sh
专门用于 Deepin 系统的调试脚本:
```bash
./debug_deepin_dbus.sh
```
## 验证修复
### 检查列表
- [ ] 程序启动时显示"ScreenLockDetector initialized successfully"
- [ ] 至少有一个接口显示"connected: true"
- [ ] 显示了正确的 session 路径(不是 "auto"
- [ ] 锁屏时看到 "LOCK SIGNAL RECEIVED" 消息
- [ ] 解锁时看到 "UNLOCK SIGNAL RECEIVED" 消息
- [ ] 主窗口状态正确更新
### 如果仍然无法接收信号
1. **运行 test_lock_signals.sh**
```bash
./test_lock_signals.sh
```
观察系统实际发出了什么信号
2. **检查会话路径**
```bash
echo $XDG_SESSION_ID
loginctl show-session $XDG_SESSION_ID
```
3. **手动测试 DBus 连接**
```bash
# 监听 system bus 的 Lock 信号
dbus-monitor --system "type='signal',interface='org.freedesktop.login1.Session',member='Lock'"
# 在另一个终端锁屏
loginctl lock-session
```
4. **检查权限**
确保用户有权限访问 system bus
```bash
groups $USER
```
用户应该在 `sudo``wheel` 组中
5. **对于 Deepin 系统**
```bash
# 列出所有 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: 可能的原因:
1. 连接到了错误的会话路径
2. 桌面环境使用了不同的锁屏机制
3. 信号签名不匹配(参数类型不对)
解决方法:使用 `test_lock_signals.sh` 查看实际信号。
### Q: 在虚拟机中测试是否会有问题?
A: 可能会。某些虚拟机可能没有完整的 session 管理。建议:
- 确保虚拟机安装了完整的桌面环境
- 使用 GUI 登录而不是 SSH
- 检查 `loginctl list-sessions` 是否显示你的会话
### Q: Deepin 系统上还是不工作怎么办?
A: Deepin 不同版本的接口可能不同:
1. 运行 `debug_deepin_dbus.sh` 找到正确的服务名
2. 修改 `connectToDeepinDDE()` 中的服务列表
3. 添加找到的服务配置
4. 重新编译测试
## 技术参考
### 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
## 总结
修复的核心要点:
1.**动态获取会话路径** - 不要硬编码 "auto"
2.**多重连接策略** - 特定路径 + 通用监听
3.**详细调试日志** - 便于诊断问题
4.**正确读取属性** - 使用 Properties 接口
5.**支持多种桌面环境** - Deepin/GNOME/KDE 等
这些修复应该能解决大多数 Linux 系统上的锁屏信号接收问题。