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