Skip to content

feat: add short idle and TLP mode support#1111

Open
xionglinlin wants to merge 1 commit into
linuxdeepin:masterfrom
xionglinlin:feat/short-idle-tlp
Open

feat: add short idle and TLP mode support#1111
xionglinlin wants to merge 1 commit into
linuxdeepin:masterfrom
xionglinlin:feat/short-idle-tlp

Conversation

@xionglinlin
Copy link
Copy Markdown
Contributor

  1. Add short idle state management with kernel file writing via dde- system-daemon
  2. Add TLP mode setting interface in system power1
  3. Implement short idle delay configuration and power saving plan
  4. Add third-party application detection to control short idle entry
  5. Add screen state from DPMS off/on events
  6. Add DSG configuration for idle paths, delays, and blacklists

Log: Added short idle state management and TLP mode configuration for power saving optimization

Influence:

  1. Test short idle entry and exit with various delay configurations
  2. Verify TLP mode switching via D-Bus interface
  3. Test third-party application detection prevents short idle entry
  4. Verify short idle blacklist and whitelist application behavior
  5. Test screen state synchronization with DPMS events
  6. Verify kernel file writing for idle and screen states
  7. Test DSG configuration changes are properly applied

feat: 添加短idle和TLP模式支持

  1. 通过dde-system-daemon添加短idle状态管理及内核文件写入功能
  2. 在系统电源管理中新增TLP模式设置接口
  3. 实现短idle延迟配置和节能计划管理
  4. 添加第三方应用检测机制以控制短idle进入
  5. 从DPMS关闭/打开事件同步屏幕状态
  6. 新增DSG配置项:空闲路径、延迟时间和黑名单

Log: 新增短idle状态管理和TLP模式配置,优化节能策略

Influence:

  1. 测试不同延迟配置下的短idle进入和退出
  2. 通过D-Bus接口验证TLP模式切换功能
  3. 测试第三方应用运行阻止短idle进入的逻辑
  4. 验证短idle黑名单和白名单应用的行为
  5. 测试屏幕状态与DPMS事件的同步
  6. 验证空闲和屏幕状态的内核文件写入
  7. 测试DSG配置变更的正确应用

PMS: TASK-389737
Change-Id: Ia3572bf438ff45f8c67e7f354f991fd6535f7775

1. Add short idle state management with kernel file writing via dde-
system-daemon
2. Add TLP mode setting interface in system power1
3. Implement short idle delay configuration and power saving plan
4. Add third-party application detection to control short idle entry
5. Add screen state from DPMS off/on events
6. Add DSG configuration for idle paths, delays, and blacklists

Log: Added short idle state management and TLP mode configuration for
power saving optimization

Influence:
1. Test short idle entry and exit with various delay configurations
2. Verify TLP mode switching via D-Bus interface
3. Test third-party application detection prevents short idle entry
4. Verify short idle blacklist and whitelist application behavior
5. Test screen state synchronization with DPMS events
6. Verify kernel file writing for idle and screen states
7. Test DSG configuration changes are properly applied

feat: 添加短idle和TLP模式支持

1. 通过dde-system-daemon添加短idle状态管理及内核文件写入功能
2. 在系统电源管理中新增TLP模式设置接口
3. 实现短idle延迟配置和节能计划管理
4. 添加第三方应用检测机制以控制短idle进入
5. 从DPMS关闭/打开事件同步屏幕状态
6. 新增DSG配置项:空闲路径、延迟时间和黑名单

Log: 新增短idle状态管理和TLP模式配置,优化节能策略

Influence:
1. 测试不同延迟配置下的短idle进入和退出
2. 通过D-Bus接口验证TLP模式切换功能
3. 测试第三方应用运行阻止短idle进入的逻辑
4. 验证短idle黑名单和白名单应用的行为
5. 测试屏幕状态与DPMS事件的同步
6. 验证空闲和屏幕状态的内核文件写入
7. 测试DSG配置变更的正确应用

PMS: TASK-389737
Change-Id: Ia3572bf438ff45f8c67e7f354f991fd6535f7775
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

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

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 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

@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

这份代码引入了一个“短空闲”电源管理机制,涉及跨进程(session/power1, system/power1, dde-system-daemon)的DBus通信、sysfs文件写入、dconfig配置读取以及第三方应用检测等功能。整体逻辑较为复杂,且涉及系统级权限操作。

以下是针对语法逻辑、代码质量、代码性能和代码安全四个方面的详细审查意见及改进建议:

一、 语法与逻辑

  1. Map 初始化与清空逻辑错误

    • 位置: session/power1/power_save_plan.go 第1381-1384行,第1398-1401行
    • 问题:
      if len(psp.manager.systemApplicationsMap) != 0 {
          psp.manager.systemApplicationsMap = make(map[string]string)
      }
      当 Map 长度不为0时,才重新 make。这意味着如果 Map 为空,将不会执行初始化,后续直接赋值会引发 panic;更严重的是,如果想要在 DConfig 变更时清空旧数据并重建 Map,此逻辑在旧数据存在时虽然会重新 make,但条件判断非常反直觉且容易埋坑。
    • 建议: 无论长度是否为0,直接重新 make 即可:
      psp.manager.systemApplicationsMap = make(map[string]string)
  2. DBus 参数类型不匹配

    • 位置: keybinding1/utils.go 第441行, session/power1/power_save_plan.go 第748行
    • 问题: SetIdleStateSetScreenStatedde-system-daemon 中的导出定义为 InArgs: []string{"state"},这通常意味着底层期望接收 bool 类型。但调用方使用了 dbus.MakeVariant(state)。虽然 dbusVariant 有时能自动解包,但这依赖于底层猜测类型,极易产生 Type mismatch 错误。
    • 建议: 直接传递 state 变量,由 dbus 库自动映射基础类型,或确保与 exported_methods_auto.go 定义的类型绝对一致:
      err = systemConn.Object(...).Call("org.deepin.dde.Daemon1.SetIdleState", 0, state).Err
  3. 状态判断逻辑漏洞

    • 位置: bin/dde-system-daemon/power.go setState 函数
    • 问题:
      shortIdleState, err := d.systemPower.ShortIdleState().Get(0)
      // ...
      if shortIdleState == state {
          logger.Info("shortIdleState is same with state : ", state)
          return errors.New("Short idle state not exchange.")
      }
      如果 Get(0) 发生错误,shortIdleState 会是零值。此时如果 state 也是 false,会错误地命中 shortIdleState == state 并返回错误,跳过了后续的文件写入逻辑。
    • 建议: 当获取状态失败时,不应作为状态相等的依据,应继续执行或返回获取失败的错误:
      shortIdleState, err := d.systemPower.ShortIdleState().Get(0)
      if err != nil {
          logger.Warning("Get systemPower.ShortIdleState err :", err)
          // 获取失败时,不阻止后续写入操作,或者直接 return err
      } else if shortIdleState == state {
          return errors.New("Short idle state not exchange.")
      }

二、 代码质量

  1. 硬编码的 Magic Sleep

    • 位置: session/power1/power_save_plan.go 第756行
    • 问题: time.Sleep(300 * time.Millisecond) 硬编码等待,通常是为了等待 DConfig 异步生效。这种做法不仅不可靠(在慢速机器上可能不够),还会阻塞当前 goroutine,降低代码可读性。
    • 建议: 如果 callSetIdleState 依赖 DConfig 的值,应当通过监听 DConfig 的 ValueChanged 信号来触发后续动作,形成事件驱动;若必须同步,应考虑在 DBus 接口层保证状态一致性。
  2. 废弃的 ioutil

    • 位置: bin/dde-system-daemon/power.go
    • 问题: 使用了 ioutil.ReadFileioutil.WriteFile。自 Go 1.16 起,ioutil 包已被废弃。
    • 建议: 替换为 os.ReadFileos.WriteFile
  3. 冗余的第三方应用判断逻辑

    • 位置: session/power1/power_save_plan.go isThirdPartyAppRunning 函数
    • 问题:
      if strings.Contains(desktop, "deepin") || strings.Contains(desktop, "dde") || strings.Contains(desktop, "uos") {
          logger.Warning("Need add systemApplicationsMap, Running app : ", app, desktop)
          continue
      }
      这种基于字符串包含关系的“容错”逻辑非常脆弱。如果第三方应用名字包含 deepin(如 deepin-wine 等),将被错误放行。白名单机制应当严格依赖配置文件。
    • 建议: 删除此容错逻辑,如果系统应用漏配,应当修改 DConfig 的白名单配置,而不是在代码里做模糊匹配。
  4. 重复代码

    • 位置: session/power1/power_save_plan.gokeybinding1/utils.gocallSetScreenState 被定义了两次。
    • 建议: 将其抽离到公共的 utils 包或 power1 模块的底层工具类中,避免代码重复。

三、 代码性能

  1. 高频 Idle 检测中的重量级 DBus 调用

    • 位置: session/power1/power_save_plan.go isThirdPartyAppRunning -> getLaunchedApplications
    • 问题: GetManagedObjects 会返回系统中所有 AM 对象的完整数据,这会带来大量的 DBus 数据序列化/反序列化开销。如果 isThirdPartyAppRunning 被频繁调用(例如每次检测空闲状态时),将造成显著的性能损耗。
    • 建议:
      • 不要每次都实时调用 GetManagedObjects
      • 应该在初始化时调用一次,并监听 AM 的 InterfacesAdded / InterfacesRemoved 信号,在内存中维护一个当前运行应用的缓存。isThirdPartyAppRunning 只需查询内存缓存即可。
  2. 无意义的 syscall.Sync

    • 位置: bin/dde-system-daemon/power.go setState 函数
    • 问题: syscall.Sync() 会将整个操作系统的所有文件系统缓存刷入磁盘。这对于仅仅写入一个 sysfs 节点来说极其昂贵,会导致全局 I/O 阻塞。
    • 建议: sysfs 是虚拟文件系统,写入是直接映射到内核回调的,不需要文件系统级别的 Sync。直接删除 syscall.Sync()

四、 代码安全

  1. 路径遍历漏洞

    • 位置: bin/dde-system-daemon/power.go setState 函数
    • 问题: file 参数来源于 DConfig(d.idleStatePathd.idleScreenStatePath)。虽然 DConfig 默认是只读的,但拥有高级权限的用户(或通过其他漏洞篡改 DConfig 的攻击者)可以将其修改为 /etc/shadow/etc/passwd 或其他任意关键文件。由于 dde-system-daemon 具有 root 权限,ioutil.WriteFile 将以 root 身份向恶意路径写入 01,从而破坏系统文件。
    • 建议: 必须对传入的路径进行严格校验,例如限定只能写入 /sys/devices/system/loongarch/ 目录下:
      import "path/filepath"
      
      func (d *Daemon) setState(file string, state bool) error {
          // 清理路径并检查前缀,防止路径遍历
          absPath, err := filepath.Abs(file)
          if err != nil || !strings.HasPrefix(absPath, "/sys/devices/system/loongarch/") {
              return fmt.Errorf("invalid file path: %s", file)
          }
          // ... 继续原有逻辑
      }
  2. 文件权限设置不当

    • 位置: bin/dde-system-daemon/power.go setState 函数
    • 问题: ioutil.WriteFile(file, []byte(newContent), 0644)。对于 sysfs 属性节点,通常不需要可执行权限,且有些内核驱动对权限要求严格。更重要的是,如果是新建文件(虽然 sysfs 一般不新建),0644 允许其他用户读取内核硬件状态,可能泄露硬件信息。
    • 建议: 将权限改为 06000200(仅 root 可写/可读写):
      err = os.WriteFile(absPath, []byte(newContent), 0600)
  3. 临时 systemd 单元执行命令的安全风险

    • 位置: system/power1/manager_powersave.go setDPCWifiState 函数
    • 问题: 使用 StartTransientUnit 运行 /usr/sbin/deepin-power-control。如果此二进制文件被恶意替换,将以 root 权限执行恶意代码。
    • 建议: 确保该二进制文件的权限正确(如属于 root 且权限为 0755,并拥有有效的签名/校验)。如果系统支持,建议通过 SELinux/AppArmor 对其进行强制访问控制保护。

Copy link
Copy Markdown
Contributor

@mhduiy mhduiy left a comment

Choose a reason for hiding this comment

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

Code Review: PR #1111

整体功能完整,涵盖了短 idle 管理、TLP 模式、第三方应用检测、DSG 配置等。以下按严重程度分级列出问题和建议:


🔴 需要修复的问题

1. system/power1/manager.go - setTlpMode 未更新 m.TlpMode 字段

func (m *Manager) setTlpMode(mode string) error {
    if m.TlpMode == mode {
        return errors.New("repeat set tlp mode")
    }
    // ... 设置 DSPCState
    return nil
}

问题m.TlpMode 从未被赋值为新的 mode,导致"重复设置"的保护逻辑完全无效,每次都会重新执行 setDSPCState
建议:在设置成功后更新 m.TlpMode = mode

2. session/power1/power_save_plan.go - Map 并发读写竞态

systemApplicationsMapshortIdleBlackListApplicationsMap 在以下场景存在竞态:

  • initDsgConfigValueChanged 回调中写 map(在 signalLoop goroutine 中)
  • isThirdPartyAppRunning 中读 map(在 metaTask 执行中)
  • 没有任何 mutex 保护,可能触发 concurrent map read and map write panic。
    建议:使用 sync.RWMutex 保护这两个 map 的读写,或者使用 sync.Map

3. bin/dde-system-daemon/main.go - _daemon.service 重复赋值

_daemon = &Daemon{
    service:             service,
    // ...
}
_daemon.getDsgValue()  // getDsgValue 中创建了自己的 configManager 连接
_daemon.service = service  // ← 重复赋值,无意义

建议:删除第 121 行的 _daemon.service = service

4. system/power1/manager.go - doSetMode 中的延时 hack

time.AfterFunc(500*time.Millisecond, func() {
    err := m.setTlpMode(ddePowerSave)
    // ...
})

问题:用固定 500ms 延时来规避 deepin-power-control 连续调用失败的问题,这是治标不治本的方案。在高负载或低性能设备上 500ms 可能不够,在正常设备上又浪费时间。
建议:修复 deepin-power-control 连续调用的根本问题,或至少增加重试逻辑 + 上限超时。


🟡 建议改进

5. bin/dde-system-daemon/power.go - 使用已废弃的 ioutil

content, err := ioutil.ReadFile(file)
err = ioutil.WriteFile(file, []byte(newContent), 0644)

建议:替换为 os.ReadFileos.WriteFileioutil 自 Go 1.16 起已废弃)。

6. bin/dde-system-daemon/power.go - isStrInList 重复造轮子

func isStrInList(item string, items []string) bool {

建议:如果项目 Go 版本 ≥ 1.21,使用 slices.Contains(item, items) 替代。

7. bin/dde-system-daemon/power.go - setStateshortIdleState 零值问题

shortIdleState, err := d.systemPower.ShortIdleState().Get(0)
if err != nil {
    logger.Warning("Get systemPower.ShortIdleState err :", err)
}
// 如果出错,shortIdleState 为零值 false
if shortIdleState == state {
    return errors.New("Short idle state not exchange.")
}

问题:D-Bus 调用失败时 shortIdleState 默认为 false,如果传入的 state 也是 false,会误判为"状态未变化"并返回错误。
建议:D-Bus 调用失败时应该直接返回错误,而不是继续判断。

8. session/power1/power_save_plan.go - changeShortIdleState 阻塞 sleep

func (psp *powerSavePlan) changeShortIdleState(state bool) {
    // ...
    psp.setDsg(dsettingsShortIdleState, state)
    time.Sleep(300 * time.Millisecond)  // ← 阻塞 300ms
    callSetIdleState(state)
}

问题:在 metaTask 执行路径中阻塞 300ms,可能影响其他电源状态转换的响应时间。
建议:使用 time.AfterFunc 或在 goroutine 中处理,避免阻塞主流程。

9. session/power1/power_save_plan.go - getLaunchedApplications 性能问题

func getLaunchedApplications() []string {
    // 同步 D-Bus 调用,获取所有应用实例
}

问题:每次检查是否进入短 idle 时,都会同步查询 ApplicationManager 获取所有运行中的应用。在系统运行大量应用时,这可能导致明显的延迟。
建议:考虑缓存应用列表,或通过信号增量更新,而非每次全量查询。

10. session/power1/power_save_plan.go - isThirdPartyAppRunning 的启发式判断

if strings.Contains(desktop, "deepin") || strings.Contains(desktop, "dde") || strings.Contains(desktop, "uos") {
    logger.Warning("Need add systemApplicationsMap, Running app : ", app, desktop)
    continue
}

问题:仅通过文件名包含 deepin/dde/uos 来判断是否为系统应用过于宽泛,且日志级别为 Warning 但实际是正常业务逻辑。第三方应用也可能包含这些字符串。
建议:严格依赖 systemApplications 配置列表,如果发现缺失项应补充到配置中,而非运行时猜测。日志级别改为 Debug

11. system/power1/manager.go - setTlpModesetShortIdleState 中 goroutine 无错误反馈

go m.setDSPCState(_powerConfigMap[mode].DSPCConfig)
// ...
go func() {
    m.setDSPCState(_powerConfigMap[powerState].DSPCConfig)
    m.setDPCWifiState(wifiState)
}()

问题:异步执行但无任何错误处理或完成确认。如果设置失败,调用方完全无感知。
建议:至少添加错误日志;如果调用方需要知道结果,考虑使用 channel 或 callback。

12. 硬编码 LoongArch 路径缺乏架构保护

const (
    IdleFile       = "/sys/devices/system/loongarch/relax_state"
    IdleScreenFile = "/sys/devices/system/loongarch/idle_state"
)

问题:这些路径仅适用于 LoongArch 架构,在 x86/ARM 设备上文件不存在。
建议:添加架构检查(runtime.GOARCH),或在 getDsgValue 中通过 DSG 配置覆盖路径(当前已有此机制,但默认值仍会初始化为 LoongArch 路径)。

13. misc/dsg-configs/org.deepin.dde.daemon.power.json - shortIdleState 权限

"shortIdleState": {
    "permissions": "readwrite",
    "visibility": "private"
}

问题shortIdleState 被 session 侧和 system 侧同时写入,谁是权威来源?建议明确文档说明,或改为仅由一侧写入。


✅ 做得好的地方

  • DSG 配置结构清晰,配置项命名规范
  • systemApplications 白名单机制设计合理
  • 空闲延迟配置支持插电/电池分别设置
  • DPMS 屏幕状态同步到内核节点的逻辑清晰
  • exported_methods_auto.go 遵循项目约定

"dde-lock.desktop",
"dde-clipboard.desktop",
"dde-clipboard-daemon.desktop",
"dde-launcher.desktop",
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.

1

"dde-file-manager.desktop",
"dde-computer.desktop",
"dde-trash.desktop",
"dde-control-center.desktop",
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.

1

"deepin-diskmanager.desktop",
"deepin-camera.desktop",
"deepin-data-transfer.desktop",
"deepin-ab-recovery.desktop",
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.

1

"gnome-keyring-ssh.desktop",
"gnome-keyring-pkcs11.desktop",
"gnome-keyring-secrets.desktop",
"fcitx-helper.desktop",
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.

1

"gnome-keyring-secrets.desktop",
"fcitx-helper.desktop",
"xdg-user-dirs.desktop",
"permission_manager_dbus_session_daemon.desktop",
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.

1

@deepin-bot
Copy link
Copy Markdown
Contributor

deepin-bot Bot commented May 20, 2026

TAG Bot

New tag: 6.1.90
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1117

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