ScreenLockDetector/LOCK_SIGNAL_FIX.md

331 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 锁屏信号未触发问题修复指南
## 问题描述
程序已成功连接到目标系统的 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 系统上的锁屏信号接收问题。