diff --git a/bin/dde-system-daemon/exported_methods_auto.go b/bin/dde-system-daemon/exported_methods_auto.go index a2121e943..5525008cb 100644 --- a/bin/dde-system-daemon/exported_methods_auto.go +++ b/bin/dde-system-daemon/exported_methods_auto.go @@ -81,5 +81,15 @@ func (v *Daemon) GetExportedMethods() dbusutil.ExportedMethods { Fn: v.SetReadOnlyProtection, InArgs: []string{"enable"}, }, + { + Name: "SetIdleState", + Fn: v.SetIdleState, + InArgs: []string{"state"}, + }, + { + Name: "SetScreenState", + Fn: v.SetScreenState, + InArgs: []string{"state"}, + }, } } diff --git a/bin/dde-system-daemon/main.go b/bin/dde-system-daemon/main.go index 7953ce872..66976bf60 100644 --- a/bin/dde-system-daemon/main.go +++ b/bin/dde-system-daemon/main.go @@ -8,6 +8,7 @@ import ( "os" configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + systemPower "github.com/linuxdeepin/go-dbus-factory/system/org.deepin.dde.power1" // modules: _ "github.com/linuxdeepin/dde-daemon/accounts1" @@ -42,12 +43,15 @@ import ( //go:generate dbusutil-gen em -type Daemon type Daemon struct { - loginManager login1.Manager - systemSigLoop *dbusutil.SignalLoop - service *dbusutil.Service - systemd systemd1.Manager - dsSystem configManager.Manager - signals *struct { // nolint + loginManager login1.Manager + systemSigLoop *dbusutil.SignalLoop + service *dbusutil.Service + systemd systemd1.Manager + dsSystem configManager.Manager + systemPower systemPower.Power + idleStatePath string + idleScreenStatePath string + signals *struct { // nolint HandleForSleep struct { start bool } @@ -110,11 +114,15 @@ func main() { logger.SetRestartCommand("/usr/lib/deepin-daemon/dde-system-daemon") _daemon = &Daemon{ - loginManager: login1.NewManager(service.Conn()), - service: service, - systemSigLoop: dbusutil.NewSignalLoop(service.Conn(), 10), - systemd: systemd1.NewManager(service.Conn()), + loginManager: login1.NewManager(service.Conn()), + service: service, + systemSigLoop: dbusutil.NewSignalLoop(service.Conn(), 10), + systemd: systemd1.NewManager(service.Conn()), + systemPower: systemPower.NewPower(service.Conn()), + idleStatePath: IdleFile, + idleScreenStatePath: IdleScreenFile, } + _daemon.getDsgValue() _daemon.service = service _daemon.initSystemDaemonDConfig() err = service.Export(dbusPath, _daemon) diff --git a/bin/dde-system-daemon/power.go b/bin/dde-system-daemon/power.go index 75a8fbcaa..528697af6 100644 --- a/bin/dde-system-daemon/power.go +++ b/bin/dde-system-daemon/power.go @@ -1,14 +1,89 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later package main import ( - "github.com/linuxdeepin/go-lib/dbusutil" + "errors" + "fmt" + "io/ioutil" "os/exec" + "strconv" + "strings" + "syscall" + + "github.com/godbus/dbus/v5" + configManager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + "github.com/linuxdeepin/go-lib/dbusutil" + "github.com/linuxdeepin/go-lib/utils" +) + +const ( + IdleFile = "/sys/devices/system/loongarch/relax_state" + IdleScreenFile = "/sys/devices/system/loongarch/idle_state" +) + +const ( + dsettingsPowerName = "org.deepin.dde.daemon.power" + dsettingsIdleStatePath = "idleStatePath" + dsettingsIdleScreenStatePath = "idleScreenStatePath" ) +func isStrInList(item string, items []string) bool { + for _, v := range items { + if item == v { + return true + } + } + return false +} + +func (d *Daemon) getDsgValue() { + ds := configManager.NewConfigManager(d.systemSigLoop.Conn()) + + powerPath, err := ds.AcquireManager(0, dsettingsSystemDaemonID, dsettingsPowerName, "") + if err != nil { + logger.Warning(err) + return + } + + dsPower, err := configManager.NewManager(d.systemSigLoop.Conn(), powerPath) + if err != nil { + logger.Warning(err) + return + } + + keyList, err := dsPower.KeyList().Get(0) + if err != nil { + logger.Warning(err) + } + + if isStrInList(dsettingsIdleStatePath, keyList) { + v, err := dsPower.Value(0, dsettingsIdleStatePath) + if err != nil { + logger.Warning(err) + } else { + if dsgIdleStatePath, ok := v.Value().(string); ok { + d.idleStatePath = dsgIdleStatePath + logger.Info("idleStatePath : ", d.idleStatePath) + } + } + } + + if isStrInList(dsettingsIdleScreenStatePath, keyList) { + v, err := dsPower.Value(0, dsettingsIdleScreenStatePath) + if err != nil { + logger.Warning(err) + } else { + if dsgIdleScreenStatePath, ok := v.Value().(string); ok { + d.idleScreenStatePath = dsgIdleScreenStatePath + logger.Info("idleScreenStatePath : ", d.idleScreenStatePath) + } + } + } +} + // TODO: 临时方案,hwe一些机型内核wifi有问题,需要停止wifip2p扫描,待内核修改后去掉 func stopNetworkDisaplay() { err := exec.Command("killall", "deepin-network-display-daemon").Run() @@ -38,3 +113,71 @@ func (d *Daemon) forwardPrepareForSleepSignal(service *dbusutil.Service) error { } return nil } + +func (d *Daemon) systemPowerSetShortIdleState(state bool) { + logger.Info("systemPowerSetShortIdleState : ", state) + if d.systemPower != nil { + err := d.systemPower.SetShortIdleState(0, state) + if err != nil { + logger.Warning("failed to SetShortIdleState, err : ", err) + } + } +} + +func (d *Daemon) setState(file string, state bool) error { + shortIdleState, err := d.systemPower.ShortIdleState().Get(0) + if err != nil { + logger.Warning("Get systemPower.ShortIdleState err :", err) + } + logger.Infof("##### setState shortIdleState : %v, state : %v", shortIdleState, state) + if shortIdleState == state { + logger.Info("shortIdleState is same with state : ", state) + return errors.New("Short idle state not exchange.") + } + if file == d.idleStatePath { + d.systemPowerSetShortIdleState(state) + } + + // 写file内核文件 + if !utils.IsFileExist(file) { + err := fmt.Errorf("%s not found", file) + logger.Warning(err) + return err + } + + // 读取file文件内容 + content, err := ioutil.ReadFile(file) + if err != nil { + logger.Errorf("Failed to read file %s: %v", file, err) + return err + } + contentStr := strings.TrimSpace(string(content)) + + // 如果不一致,将state的值写入file + // 将true转换为1,false转换为0 + newValue := 0 + if state { + newValue = 1 + } + logger.Infof("Current content=%s, will set %v", contentStr, newValue) + // 将值写入文件 + newContent := strconv.Itoa(newValue) + err = ioutil.WriteFile(file, []byte(newContent), 0644) + if err != nil { + logger.Errorf("Failed to write file %s: %v", file, err) + return err + } + syscall.Sync() + logger.Infof("Successfully updated %s with value: %d", file, newValue) + return nil +} + +func (d *Daemon) SetIdleState(state bool) *dbus.Error { + logger.Infof("SetIdleState %s try set state: %v", d.idleStatePath, state) + return dbusutil.ToError(d.setState(d.idleStatePath, state)) +} + +func (d *Daemon) SetScreenState(state bool) *dbus.Error { + logger.Infof("SetScreenState %s try set state: %v", d.idleScreenStatePath, state) + return dbusutil.ToError(d.setState(d.idleScreenStatePath, state)) +} diff --git a/keybinding1/utils.go b/keybinding1/utils.go index f55104e04..4070e4835 100644 --- a/keybinding1/utils.go +++ b/keybinding1/utils.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -319,6 +319,8 @@ func (m *Manager) systemTurnOffScreen() { } if err != nil { logger.Warning("Set DPMS off error:", err) + } else { + callSetScreenState(true) } if bScreenBlackLock && m.isWmBlackScreenActive() { @@ -436,6 +438,23 @@ func (m *Manager) doLock(autoStartAuth bool) { } } +func callSetScreenState(state bool) { + systemConn, err := dbus.SystemBus() + if err != nil { + logger.Warning("Failed to get system bus:", err) + return + } + + logger.Infof("callSetScreenState: calling SetScreenState with state=%v", state) + err = systemConn.Object("org.deepin.dde.Daemon1", "/org/deepin/dde/Daemon1").Call("org.deepin.dde.Daemon1.SetScreenState", 0, dbus.MakeVariant(state)).Err + if err != nil { + logger.Warning(err) + return + } + + logger.Infof("callSetScreenState: SetScreenState called successfully with state=%v", state) +} + func doPrepareSuspend() { sessionDBus, _ := dbus.SessionBus() obj := sessionDBus.Object("org.deepin.dde.Power1", "/org/deepin/dde/Power1") diff --git a/misc/dsg-configs/org.deepin.dde.daemon.power.json b/misc/dsg-configs/org.deepin.dde.daemon.power.json index 3545543be..feb508fef 100644 --- a/misc/dsg-configs/org.deepin.dde.daemon.power.json +++ b/misc/dsg-configs/org.deepin.dde.daemon.power.json @@ -577,6 +577,170 @@ "name[zh_CN]": "高性能模式开关", "description": "high performance enabled", "permissions": "readwrite" + }, + "idleStatePath": { + "value": "/sys/devices/system/loongarch/relax_state", + "serial": 0, + "flags": [ + "global" + ], + "name": "idle state path", + "name[zh_CN]": "通知EC进入短idle的内核节点", + "description": "kernel node to notify EC of short idle state, write 1 to enter, 0 to exit", + "permissions": "readonly", + "visibility": "private" + }, + "idleScreenStatePath": { + "value": "/sys/devices/system/loongarch/idle_state", + "serial": 0, + "flags": [ + "global" + ], + "name": "idle screen state path", + "name[zh_CN]": "通知EC显示器开关状态的内核节点", + "description": "kernel node to notify EC of display state, write 1 to turn off, 0 to turn on", + "permissions": "readonly", + "visibility": "private" + }, + "linePowerShortIdleDelay": { + "value": 300, + "serial": 0, + "flags": [], + "name": "line power short idle delay", + "name[zh_CN]": "插电时短idle延时", + "description": "line power short idle delay", + "permissions": "readwrite", + "visibility": "public" + }, + "batteryShortIdleDelay": { + "value": 300, + "serial": 0, + "flags": [], + "name": "battery short idle delay", + "name[zh_CN]": "使用电池时短idle延时", + "description": "battery short idle delay", + "permissions": "readwrite", + "visibility": "public" + }, + "shortIdleEnable": { + "value": false, + "serial": 0, + "flags": [ + "global" + ], + "name": "short idle enable", + "name[zh_CN]": "是否开启短idle方案", + "description": "enable short idle feature, readonly, override via os-config", + "permissions": "readonly", + "visibility": "private" + }, + "shortIdleState": { + "value": false, + "serial": 0, + "flags": [ + "global" + ], + "name": "short idle state", + "name[zh_CN]": "短idle状态", + "description": "current short idle state, true means entered short idle", + "permissions": "readwrite", + "visibility": "private" + }, + "shortIdleBlacklistApplications": { + "value": [ + "org.deepin.browser.desktop", + "deepin-terminal.desktop" + ], + "serial": 0, + "flags": [ + "global" + ], + "name": "short idle blacklist applications", + "name[zh_CN]": "短idle黑名单应用列表", + "description": "applications that prevent entering short idle when running", + "permissions": "readwrite", + "visibility": "private" + }, + "systemApplications": { + "value": [ + "dde-lock.desktop", + "dde-clipboard.desktop", + "dde-clipboard-daemon.desktop", + "dde-launcher.desktop", + "dde-file-manager.desktop", + "dde-computer.desktop", + "dde-trash.desktop", + "dde-control-center.desktop", + "dde-printer.desktop", + "dde-calendar.desktop", + "dde-introduction.desktop", + "dde-cooperation.desktop", + "dde-update-autostart.desktop", + "dde-calendar-service.desktop", + "deepin-app-store.desktop", + "deepin-music.desktop", + "deepin-movie.desktop", + "deepin-screen-recorder.desktop", + "deepin-image-viewer.desktop", + "deepin-album.desktop", + "deepin-draw.desktop", + "deepin-reader.desktop", + "deepin-editor.desktop", + "deepin-mail.desktop", + "deepin-voice-note.desktop", + "deepin-manual.desktop", + "deepin-system-monitor.desktop", + "deepin-boot-maker.desktop", + "deepin-devicemanager.desktop", + "deepin-log-viewer.desktop", + "deepin-calculator.desktop", + "deepin-font-manager.desktop", + "deepin-compressor.desktop", + "deepin-deb-installer.desktop", + "deepin-diskmanager.desktop", + "deepin-camera.desktop", + "deepin-data-transfer.desktop", + "deepin-ab-recovery.desktop", + "deepin-activator-notify.desktop", + "deepin-defender.desktop", + "deepin-defender-session-daemon.desktop", + "deepin-defender-nativirus-security.desktop", + "deepin-defender-nativirus.desktop", + "deepin-defender-security.desktop", + "deepin-defender-session-daemon-security.desktop", + "uos-service-support.desktop", + "uos-remote-assistance.desktop", + "uos-recovery-gui.desktop", + "uos-ai-assistant.autostart.desktop", + "auth-dialog.desktop", + "udcp-vnc-exec.desktop", + "udcp-session-exec.desktop", + "udcp-wizzard-exec.desktop", + "org.deepin.scanner.desktop", + "org.remmina.Remmina.desktop", + "booster-dtkwidget.desktop", + "gnome-keyring-ssh.desktop", + "gnome-keyring-pkcs11.desktop", + "gnome-keyring-secrets.desktop", + "fcitx-helper.desktop", + "xdg-user-dirs.desktop", + "permission_manager_dbus_session_daemon.desktop", + "downloader.desktop", + "geoclue-demo-agent.desktop", + "filearmor_notify.desktop", + "im-launch.desktop", + "oom-score-adjust.desktop", + "pulseaudio.desktop" + ], + "serial": 0, + "flags": [ + "global" + ], + "name": "system applications", + "name[zh_CN]": "系统预装应用列表", + "description": "system pre-installed applications whitelist for short idle", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/session/power1/constant.go b/session/power1/constant.go index 3fcea1f0f..3b4c91b9c 100644 --- a/session/power1/constant.go +++ b/session/power1/constant.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -56,6 +56,12 @@ const ( dsettingCustomShutdownWeekDays = "customShutdownWeekDays" dsettingShutdownCountdown = "shutdownCountdown" dsettingNextShutdownTime = "nextShutdownTime" + dsettingsSystemApplications = "systemApplications" + dsettingsShortIdleState = "shortIdleState" + dsettingsShortIdleEnable = "shortIdleEnable" + dsettingsShortIdleBlacklistApplications = "shortIdleBlacklistApplications" + dsettingsLinePowerShortIdleDelay = "linePowerShortIdleDelay" + dsettingsBatteryShortIdleDelay = "batteryShortIdleDelay" ) const ( diff --git a/session/power1/manager.go b/session/power1/manager.go index 3fa37819d..09d3cd452 100644 --- a/session/power1/manager.go +++ b/session/power1/manager.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -143,6 +143,11 @@ type Manager struct { // 使用电池时,不做任何操作,到睡眠的时间 BatterySleepDelay int `prop:"access:rw"` + // 接通电源时,不做任何操作,到短idle的时间 + LinePowerShortIdleDelay int `prop:"access:rw"` + // 使用电池时,不做任何操作,到短idle的时间 + BatteryShortIdleDelay int `prop:"access:rw"` + // 关闭屏幕前是否锁定 ScreenBlackLock bool `prop:"access:rw"` // 睡眠前是否锁定 @@ -215,6 +220,9 @@ type Manager struct { screensaverLockAtAwake bool // 是否已在进入待机流程前抓取过屏幕保护状态 screensaverStateCaptured bool + + systemApplicationsMap map[string]string + shortIdleBlackListApplicationsMap map[string]string } var _manager *Manager @@ -307,6 +315,9 @@ func newManager(service *dbusutil.Service) (*Manager, error) { m.timeDate = timedate.NewTimedate(systemBus) m.timeDate.InitSignalExt(m.systemSigLoop, true) + + m.systemApplicationsMap = make(map[string]string) + m.shortIdleBlackListApplicationsMap = make(map[string]string) return m, nil } @@ -748,6 +759,30 @@ func (m *Manager) initDBusPropCallback() { return dbusutil.ToError(err) }) + err = so.SetWriteCallback(m, "LinePowerShortIdleDelay", func(write *dbusutil.PropertyWrite) *dbus.Error { + value, ok := write.Value.(int32) + if !ok { + logger.Warning("Type is not int32") + } else { + logger.Info("LinePowerShortIdleDelay change to", value) + } + m.setPropLinePowerShortIdleDelay(int(value)) + err = m.savePowerDsgConfig(dsettingsLinePowerShortIdleDelay) + return dbusutil.ToError(err) + }) + + err = so.SetWriteCallback(m, "BatteryShortIdleDelay", func(write *dbusutil.PropertyWrite) *dbus.Error { + value, ok := write.Value.(int32) + if !ok { + logger.Warning("Type is not int32") + } else { + logger.Info("BatteryShortIdleDelay change to", value) + } + m.setPropBatteryShortIdleDelay(int(value)) + err = m.savePowerDsgConfig(dsettingsBatteryShortIdleDelay) + return dbusutil.ToError(err) + }) + err = so.SetWriteCallback(m, "LowPowerAutoSleepThreshold", func(write *dbusutil.PropertyWrite) *dbus.Error { value, ok := write.Value.(int32) if !ok { @@ -826,6 +861,9 @@ func (m *Manager) Reset() *dbus.Error { dsettingLowPowerNotifyThreshold, dsettingPercentageAction, dsettingPowerSavingModeBrightnessDropPercent, + + dsettingsLinePowerShortIdleDelay, + dsettingsBatteryShortIdleDelay, } for _, key := range settingKeys { logger.Debug("reset setting", key) @@ -971,6 +1009,10 @@ func (m *Manager) initDsg() { if init { m.savingModeBrightnessDropPercent = int32(transTypeToInt(data.Value(), 0)) } + case dsettingsLinePowerShortIdleDelay: + m.LinePowerShortIdleDelay = int(transTypeToInt(data.Value(), 300)) + case dsettingsBatteryShortIdleDelay: + m.BatteryShortIdleDelay = int(transTypeToInt(data.Value(), 300)) } // m.scheduledShutdownSwitch(false, false) @@ -1006,6 +1048,8 @@ func (m *Manager) initDsg() { getDsPowerConfig(dsettingHighPerformanceEnabled, true) getDsPowerConfig(dsettingLowPowerNotifyThreshold, true) getDsPowerConfig(dsettingPercentageAction, true) + getDsPowerConfig(dsettingsLinePowerShortIdleDelay, true) + getDsPowerConfig(dsettingsBatteryShortIdleDelay, true) m.dsPowerConfigManager.InitSignalExt(m.systemSigLoop, true) m.dsPowerConfigManager.ConnectValueChanged(func(key string) { @@ -1093,6 +1137,10 @@ func (m *Manager) savePowerDsgConfig(key string) (err error) { value = m.LowPowerNotifyThreshold case dsettingPercentageAction: value = m.LowPowerAutoSleepThreshold + case dsettingsLinePowerShortIdleDelay: + value = m.LinePowerShortIdleDelay + case dsettingsBatteryShortIdleDelay: + value = m.BatteryShortIdleDelay } err = m.setDsgData(key, value, m.dsPowerConfigManager) if err != nil { diff --git a/session/power1/power_dbusutil.go b/session/power1/power_dbusutil.go index c07adecac..a93ed88b7 100644 --- a/session/power1/power_dbusutil.go +++ b/session/power1/power_dbusutil.go @@ -378,3 +378,29 @@ func (v *Manager) setPropIsHighPerformanceSupported(value bool) (changed bool) { func (v *Manager) emitPropChangedIsHighPerformanceSupported(value bool) error { return v.service.EmitPropertyChanged(v, "IsHighPerformanceSupported", value) } + +func (v *Manager) setPropLinePowerShortIdleDelay(value int) (changed bool) { + if v.LinePowerShortIdleDelay != value { + v.LinePowerShortIdleDelay = value + v.emitPropChangedLinePowerShortIdleDelay(value) + return true + } + return false +} + +func (v *Manager) emitPropChangedLinePowerShortIdleDelay(value int) error { + return v.service.EmitPropertyChanged(v, "LinePowerShortIdleDelay", value) +} + +func (v *Manager) setPropBatteryShortIdleDelay(value int) (changed bool) { + if v.BatteryShortIdleDelay != value { + v.BatteryShortIdleDelay = value + v.emitPropChangedBatteryShortIdleDelay(value) + return true + } + return false +} + +func (v *Manager) emitPropChangedBatteryShortIdleDelay(value int) error { + return v.service.EmitPropertyChanged(v, "BatteryShortIdleDelay", value) +} diff --git a/session/power1/power_save_plan.go b/session/power1/power_save_plan.go index 485da11d9..9df51f82a 100644 --- a/session/power1/power_save_plan.go +++ b/session/power1/power_save_plan.go @@ -59,6 +59,7 @@ type powerSavePlan struct { modeBeforeIdle string allowScreenSaver bool isIdle bool + shortIdleEnable bool } func newPowerSavePlan(manager *Manager) (string, submodule, error) { @@ -109,7 +110,8 @@ func (psp *powerSavePlan) initSettingsChangedHandler() { case dsettingLinePowerScreensaverDelay, dsettingLinePowerScreenBlackDelay, dsettingLinePowerLockDelay, - dsettingLinePowerSleepDelay: + dsettingLinePowerSleepDelay, + dsettingsLinePowerShortIdleDelay: if !m.OnBattery { logger.Debug("Change OnLinePower plan") psp.OnLinePower() @@ -118,7 +120,8 @@ func (psp *powerSavePlan) initSettingsChangedHandler() { case dsettingBatteryScreensaverDelay, dsettingBatteryScreenBlackDelay, dsettingBatteryLockDelay, - dsettingBatterySleepDelay: + dsettingBatterySleepDelay, + dsettingsBatteryShortIdleDelay: if m.OnBattery { logger.Debug("Change OnBattery plan") psp.OnBattery() @@ -135,7 +138,8 @@ func (psp *powerSavePlan) OnBattery() { m := psp.manager psp.Update(int32(m.BatteryScreensaverDelay), int32(m.BatteryLockDelay), int32(m.BatteryScreenBlackDelay), - int32(m.BatterySleepDelay)) + int32(m.BatterySleepDelay), + int32(m.BatteryShortIdleDelay)) } func (psp *powerSavePlan) OnLinePower() { @@ -143,7 +147,8 @@ func (psp *powerSavePlan) OnLinePower() { m := psp.manager psp.Update(int32(m.LinePowerScreensaverDelay), int32(m.LinePowerLockDelay), int32(m.LinePowerScreenBlackDelay), - int32(m.LinePowerSleepDelay)) + int32(m.LinePowerSleepDelay), + int32(m.LinePowerShortIdleDelay)) } func (psp *powerSavePlan) Reset() { @@ -443,14 +448,14 @@ func (mts metaTasks) setRealDelay(min int32) { } func (psp *powerSavePlan) Update(screenSaverStartDelay, lockDelay, - screenBlackDelay, sleepDelay int32) { + screenBlackDelay, sleepDelay, shortIdleDelay int32) { psp.mu.Lock() defer psp.mu.Unlock() psp.interruptTasks() logger.Debugf("update(screenSaverStartDelay=%vs, lockDelay=%vs,"+ - " screenBlackDelay=%vs, sleepDelay=%vs)", - screenSaverStartDelay, lockDelay, screenBlackDelay, sleepDelay) + " screenBlackDelay=%vs, sleepDelay=%vs, shortIdleDelay=%vs)", + screenSaverStartDelay, lockDelay, screenBlackDelay, sleepDelay, shortIdleDelay) // 按照优先级 待机=屏保>关闭显示器=自动锁屏 tasks := make(metaTasks, 0, 5) @@ -486,6 +491,14 @@ func (psp *powerSavePlan) Update(screenSaverStartDelay, lockDelay, }) } + if shortIdleDelay > 0 { + tasks = append(tasks, metaTask{ + name: "shortIdleDelay", + delay: shortIdleDelay, + fn: psp.startShortIdleState, + }) + } + min := tasks.min() err := psp.setScreenSaverTimeout(min) if err != nil { @@ -588,6 +601,195 @@ func (psp *powerSavePlan) lock() { psp.manager.doLock(true) } +func (psp *powerSavePlan) getDesktopName(value string) (ret string) { + if !strings.Contains(value, "/") { + ret = value + return ret + } + parts := strings.Split(value, "/") + partsLength := len(parts) + if partsLength >= 1 { + ret = parts[partsLength-1] + logger.Info("getDesktopName value : ", value, ret) + } + return ret +} + +func getLaunchedApplications() []string { + bus, err := dbus.SessionBus() + if err != nil { + logger.Warning("getLaunchedApplications: failed to get session bus:", err) + return nil + } + + obj := bus.Object("org.desktopspec.ApplicationManager1", "/org/desktopspec/ApplicationManager1") + var result map[dbus.ObjectPath]map[string]map[string]dbus.Variant + err = obj.Call("org.desktopspec.DBus.ObjectManager.GetManagedObjects", 0).Store(&result) + if err != nil { + logger.Warning("getLaunchedApplications: failed to call GetManagedObjects:", err) + return nil + } + + var launched []string + for _, interfaces := range result { + appProps, ok := interfaces["org.desktopspec.ApplicationManager1.Application"] + if !ok { + continue + } + + instancesVariant, ok := appProps["Instances"] + if !ok { + continue + } + instances := instancesVariant.Value().([]dbus.ObjectPath) + if len(instances) == 0 { + continue + } + + desktopPathVariant, ok := appProps["DesktopSourcePath"] + if !ok { + continue + } + desktopPath := desktopPathVariant.Value().(string) + if desktopPath != "" { + launched = append(launched, desktopPath) + } + } + + return launched +} + +func interfaceToArrayString(v interface{}) (d []string) { + if v == nil { + return + } + + if d, ok := v.([]string); ok { + return d + } + + if variants, ok := v.([]dbus.Variant); ok { + d = make([]string, len(variants)) + for i, variant := range variants { + if str, ok := variant.Value().(string); ok { + d[i] = str + } else { + logger.Warningf("interfaceToArrayString: variant %d is not string: %#v", i, variant.Value()) + } + } + return d + } + + logger.Warningf("interfaceToArrayString() failed: unexpected type %T, value: %#v", v, v) + return +} + +func (psp *powerSavePlan) isThirdPartyAppRunning() (ret bool) { + launchedApplications := getLaunchedApplications() + logger.Info("launched applications: ", launchedApplications) + + if psp.manager == nil { + return + } + logger.Info("system applications: ", psp.manager.systemApplicationsMap) + + // 检查启动应用的desktop,是否在系统应用psp.manager.systemApplicationsMap中 + // 只要有一个运行中的desktop不存在于psp.manager.systemApplicationsMap中,说明就有第三方应用运行 + for _, app := range launchedApplications { + desktop := strings.ToLower(psp.getDesktopName(app)) + // 如果存在短idle黑名单应用在运行,则返回true -> 不进短idle + if _, exists := psp.manager.shortIdleBlackListApplicationsMap[desktop]; exists { + logger.Info("Found shortIdle blacklist application running: ", app, desktop) + ret = true + break + } + + if _, exists := psp.manager.systemApplicationsMap[desktop]; !exists { + // 如果不存在的应用的desktop包含deepin、dde、uos说明也是系统应用,这个应用应该加到系统应用列表中 + if strings.Contains(desktop, "deepin") || strings.Contains(desktop, "dde") || strings.Contains(desktop, "uos") { + logger.Warning("Need add systemApplicationsMap, Running app : ", app, desktop) + continue + } + logger.Info("Found third-party application running: ", app, desktop) + ret = true + break + } + } + return ret +} + +func (psp *powerSavePlan) setDsg(key string, state bool) error { + if psp.dsgPower == nil { + return errors.New("dconfig interface dsgPower is nil") + } + + err := psp.dsgPower.SetValue(0, key, dbus.MakeVariant(state)) + if err != nil { + logger.Warning("setDsg failed : ", err) + } + return err +} + +// true: 进入短idle, false: 退出短idle +func (psp *powerSavePlan) changeShortIdleState(state bool) { + if !psp.shortIdleEnable { + logger.Info("short idle dsg of shortIdleEnable is close, not support.") + return + } + + if state { + if psp.isThirdPartyAppRunning() { + logger.Info("third-party application is running, Can't enter short idle.") + return + } + } + + psp.setDsg(dsettingsShortIdleState, state) + time.Sleep(300 * time.Millisecond) + callSetIdleState(state) +} + +// dde-system-daemon 写文件: /sys/devices/system/loongarch/relax_state +func callSetIdleState(state bool) { + systemConn, err := dbus.SystemBus() + if err != nil { + logger.Errorf("Failed to get system bus: %v", err) + return + } + + logger.Infof("callSetIdleState: calling SetIdleState with state=%v", state) + err = systemConn.Object("org.deepin.dde.Daemon1", "/org/deepin/dde/Daemon1").Call("org.deepin.dde.Daemon1.SetIdleState", 0, dbus.MakeVariant(state)).Err + if err != nil { + logger.Warning(err) + return + } + + logger.Infof("callSetIdleState: SetIdleState called successfully with state=%v", state) +} + +// dde-system-daemon 写文件: /sys/devices/system/loongarch/idle_state +func callSetScreenState(state bool) { + systemConn, err := dbus.SystemBus() + if err != nil { + logger.Errorf("Failed to get system bus: %v", err) + return + } + + logger.Infof("callSetScreenState: calling SetScreenState with state=%v", state) + err = systemConn.Object("org.deepin.dde.Daemon1", "/org/deepin/dde/Daemon1").Call("org.deepin.dde.Daemon1.SetScreenState", 0, dbus.MakeVariant(state)).Err + if err != nil { + logger.Warning(err) + return + } + + logger.Infof("callSetScreenState: SetScreenState called successfully with state=%v", state) +} + +func (psp *powerSavePlan) startShortIdleState() { + logger.Info("Start short idle state") + psp.changeShortIdleState(true) +} + // 降低显示器亮度,最终关闭显示器 func (psp *powerSavePlan) screenBlack() { manager := psp.manager @@ -779,6 +981,8 @@ func (psp *powerSavePlan) handleIdleOff() { defer psp.mu.Unlock() psp.isIdle = false + psp.changeShortIdleState(false) + callSetScreenState(false) if psp.manager.shouldIgnoreIdleOff() { psp.manager.setPrepareSuspend(suspendStateFinish) @@ -1157,6 +1361,51 @@ func (psp *powerSavePlan) initDsgConfig() error { } getDelayHandleIdleOffIntervalWhenScreenBlack() + getSystemApplications := func() { + v, err := dsPower.Value(0, dsettingsSystemApplications) + if err != nil { + logger.Warning(err) + return + } + dsgSystemApplications := interfaceToArrayString(v.Value()) + if len(psp.manager.systemApplicationsMap) != 0 { + psp.manager.systemApplicationsMap = make(map[string]string) + } + for _, app := range dsgSystemApplications { + psp.manager.systemApplicationsMap[strings.ToLower(psp.getDesktopName(app))] = app + } + logger.Info("system applications []string -> map : ", psp.manager.systemApplicationsMap) + } + getSystemApplications() + + getShortIdleEnable := func() { + data, err := dsPower.Value(0, dsettingsShortIdleEnable) + if err != nil { + logger.Warning(err) + return + } + psp.shortIdleEnable = data.Value().(bool) + logger.Info("dsg of shortIdleEnable : ", psp.shortIdleEnable) + } + getShortIdleEnable() + + getShortIdleBlacklistApplications := func() { + v, err := dsPower.Value(0, dsettingsShortIdleBlacklistApplications) + if err != nil { + logger.Warning(err) + return + } + dsgShortIdleBlacklistApplications := interfaceToArrayString(v.Value()) + if len(psp.manager.shortIdleBlackListApplicationsMap) != 0 { + psp.manager.shortIdleBlackListApplicationsMap = make(map[string]string) + } + for _, app := range dsgShortIdleBlacklistApplications { + psp.manager.shortIdleBlackListApplicationsMap[strings.ToLower(psp.getDesktopName(app))] = app + } + logger.Info("shortIdle blackList system applications []string -> map : ", psp.manager.shortIdleBlackListApplicationsMap) + } + getShortIdleBlacklistApplications() + dsPower.InitSignalExt(psp.systemSigLoop, true) dsPower.ConnectValueChanged(func(key string) { logger.Info("DSG org.deepin.dde.daemon.power valueChanged, key : ", key) @@ -1167,6 +1416,12 @@ func (psp *powerSavePlan) initDsgConfig() error { getDelayWakeupInterval() case dsettingsDelayHandleIdleOffIntervalWhenScreenBlack: getDelayHandleIdleOffIntervalWhenScreenBlack() + case dsettingsSystemApplications: + getSystemApplications() + case dsettingsShortIdleBlacklistApplications: + getShortIdleBlacklistApplications() + case dsettingsShortIdleEnable: + getShortIdleEnable() default: } }) diff --git a/session/power1/utils.go b/session/power1/utils.go index ae3478080..6d967e050 100644 --- a/session/power1/utils.go +++ b/session/power1/utils.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -186,6 +186,8 @@ func (m *Manager) setDPMSModeOn() { if err != nil { logger.Warning("set DPMS on error:", err) + } else { + callSetScreenState(false) } if autoWm { @@ -205,6 +207,8 @@ func (m *Manager) setDPMSModeOff() { } if err != nil { logger.Warning("set DPMS off error:", err) + } else { + callSetScreenState(true) } os.WriteFile("/tmp/dpms-state", []byte("1"), 0644) } diff --git a/system/power1/exported_methods_auto.go b/system/power1/exported_methods_auto.go index 7be7299ec..b3fda635e 100644 --- a/system/power1/exported_methods_auto.go +++ b/system/power1/exported_methods_auto.go @@ -48,5 +48,15 @@ func (v *Manager) GetExportedMethods() dbusutil.ExportedMethods { Fn: v.SetMode, InArgs: []string{"mode"}, }, + { + Name: "SetTlpMode", + Fn: v.SetTlpMode, + InArgs: []string{"mode"}, + }, + { + Name: "SetShortIdleState", + Fn: v.SetShortIdleState, + InArgs: []string{"state"}, + }, } } diff --git a/system/power1/manager.go b/system/power1/manager.go index a3e41e618..14387d932 100644 --- a/system/power1/manager.go +++ b/system/power1/manager.go @@ -7,6 +7,7 @@ package power import ( "encoding/json" "errors" + "fmt" "io/ioutil" "os" "sync" @@ -32,6 +33,8 @@ const ( dsettingsPowerSavingModeAutoBatteryPercent = "powerSavingModeAutoBatteryPercent" dsettingsPowerMappingConfig = "powerMappingConfig" dsettingsMode = "mode" + dsettingsShortIdleEnable = "shortIdleEnable" + dsettingsShortIdleState = "shortIdleState" ) type supportMode struct { @@ -90,6 +93,15 @@ type Manager struct { // 开启节能模式时保存的数据 PowerSavingModeBrightnessData string `prop:"access:rw"` + // 当前短idle状态 + ShortIdleState bool + + // 是否支持短idle方案 + shortIdleEnable bool + + // 直接设置tlp配置 + TlpMode string + // CPU频率调节模式,支持powersave和performance CpuGovernor string @@ -143,6 +155,9 @@ const ( ddeBalance = "balance" ddePerformance = "performance" ddeLowBattery = "lowBattery" // 内部使用,在对外暴露的时候,会切换成powersave + + shortIdleWifiOn = "on" + shortIdleWifiOff = "off" ) var _allPowerModeArray = []string{ @@ -418,6 +433,17 @@ func (m *Manager) initDsgConfig() error { getMode(true) getPowerMappingConfig() + getShortIdleEnable := func() { + data, err := dsPower.GetValueBool(dsettingsShortIdleEnable) + if err != nil { + logger.Warning(err) + return + } + m.shortIdleEnable = data + logger.Info("dsg of shortIdleEnable : ", m.shortIdleEnable) + } + getShortIdleEnable() + dsPower.ConnectValueChanged(func(key string) { logger.Info("dconfig org.deepin.dde.daemon.power valueChanged, key : ", key) switch key { @@ -447,6 +473,8 @@ func (m *Manager) initDsgConfig() error { return case dsettingsPowerMappingConfig: getPowerMappingConfig() + case dsettingsShortIdleEnable: + getShortIdleEnable() default: logger.Debug("Not process. valueChanged, key : ", key) } @@ -726,6 +754,74 @@ func (m *Manager) saveDsgConfig(value string) (err error) { return m.setDsgData(dsettingsMode, m.Mode, m.dsgPower) } +func (m *Manager) setTlpMode(mode string) error { + logger.Info(" setTlpMode, mode : ", mode) + if m.TlpMode == mode { + return errors.New("repeat set tlp mode") + } + if !_validPowerModeArray.Contains(mode) { + return fmt.Errorf("PowerMode %q mode is not supported", mode) + } + if mode == ddePowerSave && m.batteryLow { + mode = ddeLowBattery + } + go m.setDSPCState(_powerConfigMap[mode].DSPCConfig) + return nil +} + +// 仅对性能模式做设置,不记录状态 +// deepin-power-control idle wifi +func (m *Manager) setShortIdleState(state bool) { + logger.Info(" setShortIdleState state : ", state) + if !m.shortIdleEnable { + logger.Info("System not open dsg of shortIdleEnable.") + return + } + + if m.ShortIdleState != state { + m.ShortIdleState = state + if m.dsgPower != nil { + err := m.setDsgData(dsettingsShortIdleState, state, m.dsgPower) + if err != nil { + logger.Warning(err) + } + } + } else { + logger.Info("setShortIdleState the same state : ", state) + return + } + + // 进入短idle: + // 1. deepin-power-control idle wifi on : 执行 `wifi on` 时,启动后台守护进程,开始监测无线网卡流量并在空闲时启用节能 + // 2. 电源模式切换为节能模式 + // 3. 进入短idle时,如果电量<=20%,则设置节能模式为lowBattery,否则为powersave + wifiState := shortIdleWifiOn + powerState := ddePowerSave + if m.batteryLow { + powerState = ddeLowBattery + } + if !m.ShortIdleState { + // 退出短idle: + // 1. deepin-power-control idle wifi off : 执行 `wifi off` 时,停止守护进程,恢复网卡默认行为 + // 2. 电源模式切换为节能模式 + // 3. 退出短idle时,如果电量<=20%,此时如果Mode为节能模式,则设置tlp模式为lowBattery,否则为powersave + wifiState = shortIdleWifiOff + + if m.Mode == ddePowerSave && m.batteryLow { + powerState = ddeLowBattery + } else { + powerState = m.Mode + } + } + go func() { + // 设置电源模式,仅设置tlp,不记录 + m.setDSPCState(_powerConfigMap[powerState].DSPCConfig) + + // 设置wifi短idle模式 + m.setDPCWifiState(wifiState) + }() +} + func (m *Manager) doSetMode(mode string) { logger.Info(" doSetMode, mode : ", mode) if !_validPowerModeArray.Contains(mode) { @@ -757,6 +853,18 @@ func (m *Manager) doSetMode(mode string) { if modeChanged { _ = m.setDsgData(dsettingsMode, fixMode, m.dsgPower) } + + logger.Info(" doSetMode, shortIdleState : ", m.ShortIdleState) + // 如果恢复性能模式时,当前处于短idle状态,则需要恢复模式后,将TlpMode设置为节能模式 + if m.ShortIdleState { + // 连续两次调用deepin-power-control,有概率会设置失败,因此使用延时500ms + time.AfterFunc(500*time.Millisecond, func() { + err := m.setTlpMode(ddePowerSave) + if err != nil { + logger.Warning(err) + } + }) + } } // 需求: 为了提高启动速度,登录前将性能模式设置为performance diff --git a/system/power1/manager_ifc.go b/system/power1/manager_ifc.go index 73b85880e..4e663d136 100644 --- a/system/power1/manager_ifc.go +++ b/system/power1/manager_ifc.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -106,6 +106,17 @@ func (m *Manager) SetMode(mode string) *dbus.Error { return nil } +func (m *Manager) SetTlpMode(mode string) *dbus.Error { + logger.Info("SetTlpMode : ", mode) + return dbusutil.ToError(m.setTlpMode(mode)) +} + +func (m *Manager) SetShortIdleState(state bool) *dbus.Error { + logger.Info(" SetShortIdleState : ", state) + m.setShortIdleState(state) + return nil +} + func (m *Manager) LockCpuFreq(governor string, lockTime int32) *dbus.Error { // TODO 改用tlp // currentGovernor, err := m.cpus.GetGovernor() diff --git a/system/power1/manager_powersave.go b/system/power1/manager_powersave.go index 66aecb564..bb5710b3b 100644 --- a/system/power1/manager_powersave.go +++ b/system/power1/manager_powersave.go @@ -44,7 +44,39 @@ var _powerConfigMap = map[string]*powerConfig{ }, } +func (m *Manager) setDPCWifiState(state string) error { + logger.Infof("setDPCWifiState, state: %s", state) + m.dspcMu.Lock() + defer m.dspcMu.Unlock() + conn, err := dbus.SystemBus() + if err != nil { + logger.Warning("Failed to connect to system bus:", err) + return err + } + + unitName := "dde-system-power-control-wifi.service" + unitInfo := systemdunit.TransientUnit{ + Dbus: conn, + UnitName: unitName, + Type: "oneshot", + Description: "Transient Unit set deepin power control wifi state", + Environment: []string{}, + Commands: []string{"/usr/sbin/deepin-power-control", "idle", "wifi", state}, + } + err = unitInfo.StartTransientUnit() + if err != nil { + logger.Warningf("failed create unit: %v, err: %v", unitName, err) + return err + } + if !unitInfo.WaitforFinish(m.systemSigLoop) { + logger.Warningf("%v run failed", unitName) + return err + } + return nil +} + func (m *Manager) setDSPCState(state DSPCMode) { + logger.Infof("setDSPCState, state: %s", state) m.dspcMu.Lock() defer m.dspcMu.Unlock() conn, err := dbus.SystemBus() @@ -93,7 +125,7 @@ func (m *Manager) updatePowerMode(init bool) { } logger.Infof("PowerSavingModeAuto: %v\n OnBattery:%v \n PowerSavingModeAutoWhenBatteryLow:%v \n batteryLow:%v \n", m.PowerSavingModeAuto, m.OnBattery, m.PowerSavingModeAutoWhenBatteryLow, m.batteryLow) - logger.Infof("lastMode: %v", m.lastMode) + logger.Infof("lastMode: %v, ShortIdleState : %v", m.lastMode, m.ShortIdleState) if !m.PowerSavingModeAuto && !m.PowerSavingModeAutoWhenBatteryLow && !init { return }