Skip to content

feat: recover power mode after sleep/shutdown/reboot#208

Merged
xionglinlin merged 1 commit into
linuxdeepin:masterfrom
xionglinlin:master
Jun 8, 2026
Merged

feat: recover power mode after sleep/shutdown/reboot#208
xionglinlin merged 1 commit into
linuxdeepin:masterfrom
xionglinlin:master

Conversation

@xionglinlin

Copy link
Copy Markdown
Contributor

When performing shutdown, reboot, hibernate or suspend operations, switch to performance mode before the operation, and restore the user's configured power mode upon wake or next startup. This ensures smooth transitions and optimal performance during these critical operations.

Key changes:

  1. Add setTlpMode() helper function to set power mode via D-Bus
  2. Add recoverySystemPowerMode() to restore user's configured power mode after wake
  3. Call setTlpMode(Performance) before shutdown, reboot, hibernate, and suspend
  4. Connect to PrepareForSleep signal to restore mode after sleep wake
  5. On startup, schedule recovery of power mode via timer

Log: Optimized power management behavior during system suspend/ hibernate/reboot/shutdown

Influence:

  1. Test shutdown: verify system switches to performance mode before shutdown
  2. Test reboot: verify performance mode is set before reboot
  3. Test hibernate: verify performance mode is set before hibernation
  4. Test suspend: verify performance mode is set before suspend
  5. Test wake from sleep: verify user's original power mode is restored
  6. Test startup: verify power mode is restored to user's configuration
  7. Test with/without battery: verify low battery mode handling on battery ≤20%
  8. Verify D-Bus communication with org.deepin.dde.Power1 service
  9. Test error handling when D-Bus calls fail

feat: 恢复休眠/关机/重启后的电源模式

在执行关机、重启、休眠或挂起操作前,先将系统切换到高性能模式,操作完成后
(唤醒或下次启动)再恢复为用户之前配置的电源模式。这确保了这些关键操作期
间的流畅过渡和最佳性能。

主要变更:

  1. 添加 setTlpMode() 辅助函数,通过 D-Bus 设置电源模式
  2. 添加 recoverySystemPowerMode() 恢复用户配置的电源模式
  3. 在关机、重启、休眠和挂起前调用 setTlpMode(Performance)
  4. 连接 PrepareForSleep 信号,在睡眠唤醒后恢复模式
  5. 在启动时通过定时器调度恢复电源模式

Log: 优化系统挂起/休眠/重启/关机时的电源管理行为

Influence:

  1. 测试关机:验证关机前是否切换为高性能模式
  2. 测试重启:验证重启前是否设置为高性能模式
  3. 测试休眠:验证休眠前是否设置为高性能模式
  4. 测试挂起:验证挂起前是否设置为高性能模式
  5. 测试从睡眠唤醒:验证是否恢复用户原始电源模式
  6. 测试启动:验证电源模式是否恢复为用户配置
  7. 测试有/无电池情况:验证电池电量≤20%时的低电量模式处理
  8. 验证与 org.deepin.dde.Power1 服务的 D-Bus 通信
  9. 测试 D-Bus 调用失败时的错误处理

PMS: TASK-389737
Change-Id: I30122c303b2b61a4912a554ccfb0d75dce3747a1

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @xionglinlin, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

fly602
fly602 previously approved these changes May 18, 2026

@mhduiy mhduiy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: PR #208

功能目标明确:在关机/重启/休眠/挂起前切换高性能模式,唤醒/启动后恢复用户配置。以下是具体问题:


🔴 需要修复的问题

1. sessionmanager.cpp - setTlpMode 异步调用导致竞态

void SessionManager::setTlpMode(const QString &mode)
{
    QDBusInterface inter(...);
    QDBusPendingReply<> reply = inter.asyncCall("SetTlpMode", mode);
    Q_UNUSED(reply)
}

void SessionManager::RequestShutdown()
{
    setTlpMode(Performance);  // 异步,不等待结果
    shutdown(true);           // 立即执行关机
}

问题setTlpMode 是异步调用,RequestShutdown/RequestReboot/RequestSuspend 不等待 TLP 模式设置完成就立即执行关机/重启/挂起。在实际场景中,关机流程可能在 TLP 模式切换完成之前就已经终止了 DDE 服务,导致高性能模式设置失败——整个功能的核心目标可能无法达成。
建议:使用 QDBusPendingCallWatcher 等待调用完成后再执行关机流程,或使用同步 call() 方式(考虑到这是关机前的一次性操作,短暂阻塞可接受)。

2. sessionmanager.cpp - recoverySystemPowerMode 同步 D-Bus 调用过多

QDBusMessage tlpMsg = inter.call("Get", "org.deepin.dde.Power1", "TlpMode");   // 同步
QDBusMessage modeMsg = inter.call("Get", "org.deepin.dde.Power1", "Mode");     // 同步
QDBusMessage batteryMsg = inter.call("Get", ..., "HasBattery");                 // 同步
QDBusMessage capacityMsg = inter.call("Get", ..., "BatteryCapacity");           // 同步

问题:最多 4 次同步 D-Bus 调用,每次调用可能耗时数十毫秒到数秒。在启动路径 (init()) 中调用时,会拖慢启动速度。在 PrepareForSleep(false) 唤醒回调中调用时,D-Bus 服务可能尚未完全就绪。
建议

  • 启动时:考虑延迟恢复或使用 QTimer::singleShot 增加重试
  • 唤醒时:先检查 D-Bus 服务是否可用,失败后延迟重试

3. sessionmanager.cpp - 电源模式字符串硬编码

static const QString Performance = QStringLiteral("performance");
static const QString PowerSave = QStringLiteral("powersave");
static const QString LowBattery = QStringLiteral("lowBattery");

问题:这些字符串必须与 dde-daemon 中的电源模式常量保持一致。如果 dde-daemon 修改了这些值,此处会静默失败。
建议:考虑通过 D-Bus 接口查询可用的模式列表,或在注释中明确标注依赖关系。LowBattery 是 dde-daemon 内部使用的值,是否应该通过 TlpMode 直接使用 dde-daemon 暴露的 Mode 属性而非自己做 battery 判断?

4. sessionmanager.cpp:567 - 启动时的 recoverySystemPowerMode 时机问题

QTimer::singleShot(0, this, [this] { recoverySystemPowerMode(); });

问题QTimer::singleShot(0) 只保证在当前事件循环迭代完成后执行,但不能保证 org.deepin.dde.Power1 的 D-Bus 服务已经就绪。在冷启动场景下,系统服务可能尚未注册到 D-Bus。
建议:添加重试机制,例如失败后每秒重试,最多 3-5 次。


🟡 建议改进

5. 电池电量阈值硬编码

if (batteryCapacity <= 20.0) {
    mode = LowBattery;
}

建议:提取为常量,并添加注释说明此阈值应与 dde-daemon 中的低电量阈值保持一致。

6. recoverySystemPowerMode 缺少成功日志

建议:在函数末尾添加 qInfo() << "Recovered power mode to:" << mode;,方便排查问题。

7. 行尾有多余空格

    QTimer::singleShot(0, this, [this] { 

建议:清理行尾空格。

8. PrepareForSleep 信号连接位置

connect(m_login1ManagerInter, &org::freedesktop::login1::Manager::PrepareForSleep, [=](bool sleep) {

建议:此 lambda 捕获了 this(通过 [=]),但这里应该使用 [this] 显式捕获,避免意外捕获其他变量。虽然当前没有其他局部变量,但 [=] 是不良实践。


🟢 整体评价

  • 功能设计思路正确:操作前切高性能,唤醒后恢复
  • PrepareForSleep 信号的使用是正确的唤醒恢复方案
  • 代码结构清晰,新增的两个方法职责单一
  • 核心风险:异步调用导致 TLP 模式可能来不及设置就关机(第 1 点),建议优先修复

mhduiy
mhduiy previously approved these changes May 18, 2026
@deepin-bot

deepin-bot Bot commented Jun 4, 2026

Copy link
Copy Markdown

TAG Bot

New tag: 2.0.25
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #212

When performing shutdown, reboot, hibernate or suspend operations,
switch to performance mode before the operation, and restore the user's
configured power mode upon wake or next startup. This ensures smooth
transitions and optimal performance during these critical operations.

Key changes:
1. Add `setTlpMode()` helper function to set power mode via D-Bus
2. Add `recoverySystemPowerMode()` to restore user's configured power
mode after wake
3. Call `setTlpMode(Performance)` before shutdown, reboot, hibernate,
and suspend
4. Connect to `PrepareForSleep` signal to restore mode after sleep wake
5. On startup, schedule recovery of power mode via timer

Log: Optimized power management behavior during system suspend/
hibernate/reboot/shutdown

Influence:
1. Test shutdown: verify system switches to performance mode before
shutdown
2. Test reboot: verify performance mode is set before reboot
3. Test hibernate: verify performance mode is set before hibernation
4. Test suspend: verify performance mode is set before suspend
5. Test wake from sleep: verify user's original power mode is restored
6. Test startup: verify power mode is restored to user's configuration
7. Test with/without battery: verify low battery mode handling on
battery ≤20%
8. Verify D-Bus communication with org.deepin.dde.Power1 service
9. Test error handling when D-Bus calls fail

feat: 恢复休眠/关机/重启后的电源模式

在执行关机、重启、休眠或挂起操作前,先将系统切换到高性能模式,操作完成后
(唤醒或下次启动)再恢复为用户之前配置的电源模式。这确保了这些关键操作期
间的流畅过渡和最佳性能。

主要变更:
1. 添加 `setTlpMode()` 辅助函数,通过 D-Bus 设置电源模式
2. 添加 `recoverySystemPowerMode()` 恢复用户配置的电源模式
3. 在关机、重启、休眠和挂起前调用 `setTlpMode(Performance)`
4. 连接 `PrepareForSleep` 信号,在睡眠唤醒后恢复模式
5. 在启动时通过定时器调度恢复电源模式

Log: 优化系统挂起/休眠/重启/关机时的电源管理行为

Influence:
1. 测试关机:验证关机前是否切换为高性能模式
2. 测试重启:验证重启前是否设置为高性能模式
3. 测试休眠:验证休眠前是否设置为高性能模式
4. 测试挂起:验证挂起前是否设置为高性能模式
5. 测试从睡眠唤醒:验证是否恢复用户原始电源模式
6. 测试启动:验证电源模式是否恢复为用户配置
7. 测试有/无电池情况:验证电池电量≤20%时的低电量模式处理
8. 验证与 org.deepin.dde.Power1 服务的 D-Bus 通信
9. 测试 D-Bus 调用失败时的错误处理

PMS: TASK-389737
Change-Id: I30122c303b2b61a4912a554ccfb0d75dce3747a1
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

我对这段代码进行了审查,以下是关于语法逻辑、代码质量、代码性能和代码安全的改进建议:

1. 语法逻辑

优点:

  • 代码结构清晰,功能模块划分合理
  • 使用了合适的Qt信号槽机制处理异步事件

改进建议:

  • recoverySystemPowerMode() 函数中的逻辑较为复杂,建议拆分为更小的函数以提高可读性
  • setTlpMode() 中使用了硬编码的DBus接口名称和路径,建议定义为常量

2. 代码质量

优点:

  • 使用了Qt的信号槽机制处理系统事件
  • 添加了适当的日志输出,便于调试

改进建议:

  • 建议为 setTlpMode()recoverySystemPowerMode() 添加更详细的注释,说明其功能和用途
  • recoverySystemPowerMode() 函数中的多个DBus调用可以考虑封装成独立的函数
  • 建议统一错误日志的输出格式,保持一致性

3. 代码性能

优点:

  • 使用了 QTimer::singleShot(0, ...) 确保初始化在事件循环中执行
  • DBus调用设置了超时时间,避免无限等待

改进建议:

  • recoverySystemPowerMode() 中连续进行了多次DBus调用,可以考虑合并某些调用或使用异步方式
  • 对于频繁调用的函数,可以考虑添加缓存机制,避免重复获取相同的系统状态

4. 代码安全

优点:

  • 对DBus调用的错误进行了检查
  • 在系统睡眠/唤醒时正确处理了电源模式恢复

改进建议:

  • setTlpMode() 中的DBus接口调用应该添加更严格的错误处理,特别是在关机/重启等关键操作前
  • 建议添加参数验证,确保传入的mode参数是有效的
  • 对于DBus接口的调用,建议添加重试机制,特别是在关键操作中

具体改进建议

  1. 添加DBus接口常量定义:
static const QString POWER_SERVICE = "org.deepin.dde.Power1";
static const QString POWER_PATH = "/org/deepin/dde/Power1";
static const QString POWER_INTERFACE = "org.deepin.dde.Power1";
static const QString PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
  1. 改进 recoverySystemPowerMode() 函数,拆分为多个子函数:
void SessionManager::recoverySystemPowerMode()
{
    qInfo() << "recoverySystemPowerMode";
    
    QString currentMode = getCurrentPowerMode();
    QString targetMode = determineTargetPowerMode(currentMode);
    
    if (currentMode != targetMode) {
        setTlpMode(targetMode);
    }
}

QString SessionManager::getCurrentPowerMode()
{
    // 获取当前电源模式的实现
}

QString SessionManager::determineTargetPowerMode(const QString &currentMode)
{
    // 根据当前模式和系统状态确定目标模式的实现
}
  1. 增强错误处理和重试机制:
void SessionManager::setTlpMode(const QString &mode, int maxRetries = 3)
{
    qInfo() << "setTlpMode mode:" << mode;
    
    QDBusInterface inter(POWER_SERVICE, POWER_PATH, POWER_INTERFACE, QDBusConnection::systemBus());
    inter.setTimeout(3000);
    
    int retryCount = 0;
    while (retryCount < maxRetries) {
        QDBusMessage reply = inter.call("SetTlpMode", mode);
        if (reply.type() != QDBusMessage::ErrorMessage) {
            return;
        }
        
        qWarning() << "SetTlpMode failed (attempt" << retryCount + 1 << "):" << reply.errorMessage();
        retryCount++;
        QThread::msleep(1000); // 等待1秒后重试
    }
    
    qCritical() << "Failed to set TlpMode after" << maxRetries << "attempts";
}
  1. 添加参数验证:
void SessionManager::setTlpMode(const QString &mode)
{
    static const QStringList validModes = {Performance, PowerSave, LowBattery};
    if (!validModes.contains(mode)) {
        qWarning() << "Invalid TLP mode:" << mode;
        return;
    }
    
    // 原有实现...
}

这些建议可以提高代码的健壮性、可维护性和性能,同时增强错误处理能力。

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mhduiy, xionglinlin

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@xionglinlin xionglinlin merged commit 25ceb10 into linuxdeepin:master Jun 8, 2026
17 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants