Skip to content

fix: restore the power mode from the active session only - #236

Merged
fly602 merged 1 commit into
linuxdeepin:masterfrom
fly602:fix/power-mode-recovery-active-session
Oct 15, 2026
Merged

fly602 merged 1 commit into
linuxdeepin:masterfrom
fly602:fix/power-mode-recovery-active-session

Conversation

@fly602

@fly602 fly602 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

On resume SessionManager restored the system power mode from the
PrepareForSleep(false) handler in every logged in session. The power mode is
system wide, so a background session wrote a mode it did not own, and because that
write comes from a session that is not the active one, polkit asks for an
administrator password instead of granting it (allow_inactive is auth_admin
while allow_active is yes).

Reported case: two logged in users, hibernate from user A, resume, switch to user B.
B's session had written the global power mode from the background and B's lock
screen showed an administrator password dialog.

This change keeps the intent (the mode configured before suspend is restored) but
restricts who may do it:

  • the recovery returns immediately unless the session owns the active login1
    session;
  • it is called both from the wakeup handler and from ActiveChanged(true), so the
    order of those two signals does not matter;
  • the write stays idempotent: it is skipped when the target mode already matches,
    and the activity state is re-checked after the power properties were read.

Verification

The state machine was exercised with the real SessionManager against an isolated
D-Bus with stub login1/Power1 services:

Scenario Before After
inactive session gets PrepareForSleep(false) SetTlpMode() issued no call, no property read
activation with an already matching mode no call no write
activation with a differing mode one call one call (granted for an active session)
second activation, mode now matching - no write
active session wake with a differing mode one call one call
background wake, then switch into the session one call at wakeup one call on activation
low battery with powersave target powersave written lowBattery written once
low battery, target already applied rewritten not rewritten
goes inactive while reading the properties write issued flag-free early return, no write

No permanent test target was added: this repository has no harness for the session
manager (the existing securityloaderhelper_test is not built by default), so the
behaviour was verified with a throwaway harness instead.

debian/changelog is intentionally not touched; the version bump is generated by the
update-changelog workflow (upstream, only chore: bump version to ... commits change
it).

Note: the recovery now runs on every activation, so the synchronous property reads
happen on each session switch. They use QDBusInterface's default timeout, as
before, and return early when the mode already matches.

Passwordless registration for the power service callers is a separate fix in
dde-services.

Summary by Sourcery

Restore the pre-suspend power mode only from the active session and make recovery safe across wakeup and session-activation events.

Bug Fixes:

  • Restrict system power-mode recovery to the active session, preventing background sessions from triggering unauthorized writes and administrator-password prompts.
  • Ensure power-mode recovery handles either wakeup or session activation ordering while avoiding writes when the target mode already matches or the session becomes inactive during recovery.

@sourcery-ai

sourcery-ai Bot commented Oct 15, 2026

Copy link
Copy Markdown

Reviewer's Guide

Power-mode recovery is now tracked as pending and performed only by the active session, with race-safe activity checks and target comparisons preventing background-session and redundant writes.

Sequence diagram for deferred power-mode recovery

sequenceDiagram
    participant Power as Power1
    participant Session as SessionManager
    participant Logind as login1 Session

    Power->>Session: PrepareForSleep(false)
    Session->>Session: m_powerModeRecoveryPending = true
    Session->>Logind: active()
    Logind-->>Session: false
    Note over Session: Recovery deferred

    Logind->>Session: ActiveChanged(true)
    Session->>Logind: active()
    Logind-->>Session: true
    Session->>Power: Get power properties
    Power-->>Session: Current mode and battery state
    Session->>Logind: active()
    Logind-->>Session: true
    alt target differs from tlpMode
        Session->>Power: setTlpMode(target)
    else target already matches
        Note over Session: Clear pending flag without writing
    end
Loading

State diagram for pending power-mode recovery

stateDiagram-v2
    [*] --> Idle
    Idle --> Pending: PrepareForSleep(false)
    Idle --> Pending: SessionManager init
    Pending --> Pending: ActiveChanged(false)
    Pending --> Reading: ActiveChanged(true)
    Reading --> Pending: becomes inactive
    Reading --> Idle: target matches current mode
    Reading --> Idle: active and target differs / setTlpMode
    Idle --> Idle: ActiveChanged(true) without pending flag
Loading

File-Level Changes

Change Details Files
Defers system-wide power-mode recovery until this logind session is active.
  • Records a pending recovery when initialization or resume occurs.
  • Triggers recovery from active-session changes instead of immediately on wakeup.
  • Guards recovery both before and after D-Bus property reads, retaining the pending flag if the session becomes inactive.
  • Avoids clearing or writing when the current mode already matches the target.
src/dde-session/impl/sessionmanager.cpp
src/dde-session/impl/sessionmanager.h
Avoids redundant low-battery power-mode writes.
  • Selects lowBattery only when battery conditions require it.
  • Compares the resolved target mode with the current mode before calling SetTlpMode().
src/dde-session/impl/sessionmanager.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@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.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

1. Gate the recovery on the active login1 session, so a background
   session no longer writes the global power mode when the system
   resumes.
2. Run the recovery from the wakeup handler and from ActiveChanged(true);
   the active check inside makes the order of those signals irrelevant.
3. Keep the write idempotent: skip it when the target mode already
   matches, and re-check activity after reading the power properties.

Log: Stop background sessions from writing the global power mode

Influence:
1. Log in as user A, switch to user B and hibernate; after resume switch
   back to A and confirm no password dialog is left on the lock screen.
2. Confirm the background session issues no SetTlpMode on wakeup (the
   user journal shows no attempt).
3. In the active session, wake up with a configured mode different from
   the applied one and confirm the mode is restored exactly once.
4. With low battery and powersave as the target, confirm the low battery
   mode is written once and not written again afterwards.

fix: 仅由活动会话恢复电源模式

1. 恢复前判断当前会话是否为活动会话,后台会话在系统唤醒时不再写入
   全局电源模式。
2. 唤醒处理与 ActiveChanged(true) 都会调用恢复;内部的 active 判断
   使这两个信号的先后顺序不影响结果。
3. 写入保持幂等:目标模式与当前一致时跳过;读取电源属性后再次校验
   会话活动状态。

Log: 避免后台会话写入全局电源模式

Influence:
1. 用户A登录后切到用户B休眠,唤醒后切回A,确认锁屏不再残留密码
   认证弹窗。
2. 确认后台会话唤醒时不调用 SetTlpMode(用户日志无相关尝试)。
3. 活动会话唤醒且配置模式与已应用模式不同时,确认模式只被恢复一次。
4. 低电量且目标为节能模式时,确认 lowBattery 写入一次且不重复写入。

PMS: BUG-379055
@fly602 fly602 changed the title fix: defer power mode recovery until the session is active fix: restore the power mode from the active session only Oct 15, 2026
@fly602
fly602 force-pushed the fix/power-mode-recovery-active-session branch from 217e466 to e18a182 Compare October 15, 2026 11:51
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 98 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 总体评分 98 分,大于 70 分通过阈值,代码质量优秀。本次变更正确修复了非活动会话恢复电源模式导致 polkit 请求管理员密码的问题,逻辑清晰,注释完整,无安全漏洞。

🔍 详细分析

1. 语法逻辑 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 语法正确,逻辑清晰,无需修改


2. 代码质量 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 建议后续为 SessionManager 的电源模式恢复逻辑添加永久单元测试,确保回归安全性


3. 代码性能 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 当前实现在模式匹配时提前返回,已最小化不必要的 DBus 调用。如后续出现性能瓶颈,可考虑异步读取属性或缓存上次读取结果


4. 代码安全 🔒

评价: 优秀 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: 无安全漏洞。本次变更实际上提升了安全性,通过限制只有活动会话才能写入系统级电源模式,避免了非活动会话触发 polkit 管理员密码弹窗的安全隐患


💡 改进建议代码示例

// 当前代码已无需修复,以下为代码审查中确认的正确实现

void SessionManager::recoverySystemPowerMode()
{
    // 电源模式是系统级的,只有活动会话可以恢复,否则会与活动会话冲突
    if (!m_login1SessionInter->active())
        return;

    // ... 读取 DBus 属性 ...

    if (mode == tlpMode)
        return;

    // ... 电池状态检查 ...

    if (mode == tlpMode)
        return;
    // 读取属性期间会话可能已变为非活动,等下次激活时再恢复
    if (!m_login1SessionInter->active())
        return;
    setTlpMode(mode);
}

本报告由 AI 代码审查工具自动生成

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

@fly602
fly602 merged commit ac1aea0 into linuxdeepin:master Oct 15, 2026
13 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.

3 participants