diff --git a/debian/control b/debian/control index f42b697fd..dabace693 100644 --- a/debian/control +++ b/debian/control @@ -108,7 +108,7 @@ Provides: Recommends: flatpak, iio-sensor-proxy, - laptop-mode-tools, + tlp, proxychains4, mesa-utils, Suggests: diff --git a/misc/dsg-configs/org.deepin.dde.daemon.power.bluetoothadapter.json b/misc/dsg-configs/org.deepin.dde.daemon.power.bluetoothadapter.json new file mode 100644 index 000000000..3c3b19684 --- /dev/null +++ b/misc/dsg-configs/org.deepin.dde.daemon.power.bluetoothadapter.json @@ -0,0 +1,30 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "enableDevices": { + "value": "up", + "serial": 0, + "flags": [ + "global" + ], + "name": "EnableDevices", + "name[zh_CN]": "启用/禁用设备", + "description": "Enable/disable the devices", + "permissions": "readwrite", + "visibility": "public" + }, + "scanDevices": { + "value": "piscan", + "serial": 0, + "flags": [ + "global" + ], + "name": "PiscanDevices", + "name[zh_CN]": "启用/禁用页面查询扫描", + "description": "Enable/disable Page and query scanning", + "permissions": "readwrite", + "visibility": "public" + } + } +} diff --git a/misc/dsg-configs/org.deepin.dde.daemon.power.tlp.json b/misc/dsg-configs/org.deepin.dde.daemon.power.tlp.json new file mode 100644 index 000000000..001ad5406 --- /dev/null +++ b/misc/dsg-configs/org.deepin.dde.daemon.power.tlp.json @@ -0,0 +1,548 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "soundPowerSaveOnAc": { + "value": "0", + "serial": 0, + "flags": [ + "global" + ], + "name": "SoundPowerSaveOnAc", + "name[zh_CN]": "连接电源状态的音频节能模式", + "description": "Audio power saving for Intel HDA on Alternating current.", + "permissions": "readwrite", + "visibility": "private" + }, + "soundPowerSaveOnBat": { + "value": "1", + "serial": 0, + "flags": [ + "global" + ], + "name": "SoundPowerSaveOnBat", + "name[zh_CN]": "电池状态的音频节能模式", + "description": "Audio power saving for Intel HDA on battery.", + "permissions": "readwrite", + "visibility": "private" + }, + "soundPowerSaveController": { + "value": "Y", + "serial": 0, + "flags": [ + "global" + ], + "name": "SoundPowerSaveController", + "name[zh_CN]": "音频节能控制器", + "description": "Audio power saving controller.", + "permissions": "readwrite", + "visibility": "private" + }, + "startChargeThreshBatPrimary": { + "value": "75", + "serial": 0, + "flags": [ + "global" + ], + "name": "StartChargeThreshBatPrimary", + "name[zh_CN]": "主电池开始充电的阈值", + "description": "Main Battery charge level below which charging will begin when connecting the charger.", + "description[zh_CN]": "", + "permissions": "readwrite", + "visibility": "private" + }, + "stopChargeThreshBatPrimary": { + "value": "80", + "serial": 0, + "flags": [ + "global" + ], + "name": "StopChargeThreshBatPrimary", + "name[zh_CN]": "主电池停止充电的阈值", + "description": "Main battery charge level above which charging will stop while the charger is connected.", + "description[zh_CN]": "", + "permissions": "readwrite", + "visibility": "private" + }, + "startChargeThreshBatSecondary": { + "value": "75", + "serial": 0, + "flags": [ + "global" + ], + "name": "StartChargeThreshBatSecondary", + "name[zh_CN]": "辅电池开始充电的阈值", + "description": "Ultrabay battery charge level below which charging will begin when connecting the charger.", + "permissions": "readwrite", + "visibility": "private" + }, + "stopChargeThreshBatSecondary": { + "value": "80", + "serial": 0, + "flags": [ + "global" + ], + "name": "StopChargeThreshBatSecondary", + "name[zh_CN]": "辅电池停止充电的阈值", + "description": "Ultrabay battery charge level above which charging will stop while the charger is connected.", + "permissions": "readwrite", + "visibility": "private" + }, + "restoreThresholdsOnBat": { + "value": "1", + "serial": 0, + "flags": [ + "global" + ], + "name": "RestoreThresholdsOnBat", + "name[zh_CN]": "恢复配置的电荷阈值", + "description": "Restore configured charge thresholds when AC is unplugged.", + "permissions": "readwrite", + "visibility": "private" + }, + "bayPoweroffOnAc": { + "value": "0", + "serial": 0, + "flags": [ + "global" + ], + "name": "BayPoweroffOnAc", + "name[zh_CN]": "使用电源时关闭光驱", + "description": "Power off optical drive in UltraBay/MediaBay", + "permissions": "readwrite", + "visibility": "private" + }, + "bayPoweroffOnBat": { + "value": "0", + "serial": 0, + "flags": [ + "global" + ], + "name": "BayPoweroffOnBat", + "name[zh_CN]": "使用电池时关闭光驱", + "description": "Power off optical drive in UltraBay/MediaBay", + "permissions": "readwrite", + "visibility": "private" + }, + "bayDevice": { + "value": "sr0", + "serial": 0, + "flags": [ + "global" + ], + "name": "BayDevice", + "name[zh_CN]": "光驱设备", + "description": "Optical drive device to power off", + "permissions": "readwrite", + "visibility": "private" + }, + "maxLostWorkSecsOnAc": { + "value": "15", + "serial": 0, + "flags": [ + "global" + ], + "name": "MaxLostWorkSecsOnAc", + "name[zh_CN]": "接入电源磁盘写入超时", + "description": "Timeout (in seconds) for writing unsaved data in file system buffers to disk", + "permissions": "readwrite", + "visibility": "private" + }, + "maxLostWorkSecsOnBat": { + "value": "60", + "serial": 0, + "flags": [ + "global" + ], + "name": "MaxLostWorkSecsOnBat", + "name[zh_CN]": "接入电池磁盘写入超时", + "description": "Timeout (in seconds) for writing unsaved data in file system buffers to disk", + "permissions": "readwrite", + "visibility": "private" + }, + "nmiWatchdog": { + "value": "0", + "serial": 0, + "flags": [ + "global" + ], + "name": "NmiWatchdog", + "name[zh_CN]": "内核NMI看门狗", + "description": "Kernel NMI Watchdog", + "permissions": "readwrite", + "visibility": "private" + }, + "wifiPwrOnAc": { + "value": "off", + "serial": 0, + "flags": [ + "global" + ], + "name": "WifiPwrOnAc", + "name[zh_CN]": "接入电源wifi节能模式", + "description": "Sets Wi-Fi power saving mode. Adapter support depends on kernel and driver. ", + "permissions": "readwrite", + "visibility": "public" + }, + "wifiPwrOnBat": { + "value": "on", + "serial": 0, + "flags": [ + "global" + ], + "name": "WifiPwrOnBat", + "name[zh_CN]": "接入电池wifi节能模式", + "description": "Sets Wi-Fi power saving mode. Adapter support depends on kernel and driver. ", + "permissions": "readwrite", + "visibility": "public" + }, + "wolDisable": { + "value": "Y", + "serial": 0, + "flags": [ + "global" + ], + "name": "WolDisable", + "name[zh_CN]": "禁用网络唤醒", + "description": "Disable wake on LAN", + "permissions": "readwrite", + "visibility": "private" + }, + "restoreDeviceStateOnStartup": { + "value": "0", + "serial": 0, + "flags": [ + "global" + ], + "name": "RestoreDeviceStateOnStartup", + "name[zh_CN]": "恢复无线设备状态", + "description": "Restores radio device state (builtin Bluetooth, Wi-Fi, WWAN) from previous shutdown on boot", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToDisableOnStartup": { + "value": "bluetooth wifi wwan", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToDisableOnStartup", + "name[zh_CN]": "启动时禁用内置无线设备", + "description": "Disables builtin radio devices on boot", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToEableOnStartup": { + "value": "wifi", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToEableOnStartup", + "name[zh_CN]": "启动时启用内置无线设备", + "description": "Radio devices to enable on startup", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToDisableOnShutdown": { + "value": "bluetooth wifi wwan", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToDisableOnShutdown", + "name[zh_CN]": "关机时禁用内置无线设备", + "description": "Disables builtin radio devices upon system shutdown. ", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToEableOnShutdown": { + "value": "wwan", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToEableOnShutdown", + "name[zh_CN]": "关机时启用内置无线设备", + "description": "Enables builtin radio devices on shutdown", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToEableOnAc": { + "value": "bluetooth wifi wwan", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToEableOnAc", + "name[zh_CN]": "接入电源时启用内置无线设备", + "description": "Enables builtin radio devices when AC power is plugged in.", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToDisableOnBat": { + "value": "bluetooth wifi wwan", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToDisableOnBat", + "name[zh_CN]": "接入电池时禁用内置无线设备", + "description": "Disables builtin radio devices when changing to battery power regardless of their connection state", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToDisableOnBatNotInUse": { + "value": "bluetooth wifi wwan", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToDisableOnBatNotInUse", + "name[zh_CN]": "当设备没有连接时,接入电源禁用内置无线设备", + "description": "Disables builtin radio devices that are not connected when changing to battery power", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToDisableOnLanConnect": { + "value": "wifi wwan", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToDisableOnLanConnect", + "name[zh_CN]": "LAN建立连接后,禁用无线设备", + "description": "When a LAN connection has been established, the stated radio devices are disabled", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToDisableOnWifiConnect": { + "value": "wwan", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToDisableOnWifiConnect", + "name[zh_CN]": "Wifi建立连接后,禁用无线设备", + "description": "When a Wifi connection has been established, the stated radio devices are disabled", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToDisableOnWwanConnect": { + "value": "wifi", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToDisableOnWwanConnect", + "name[zh_CN]": "Wwan建立连接后,禁用无线设备", + "description": "When a Wwan connection has been established, the stated radio devices are disabled", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToEableOnLanDisconnect": { + "value": "wifi wwan", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToEableOnLanDisconnect", + "name[zh_CN]": "LAN断开后,启用无线设备", + "description": "When a LAN connection has been disconnected, the stated radio devices are enabled", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToEableOnWifiDisconnect": { + "value": "", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToEableOnWifiDisconnect", + "name[zh_CN]": "wifi断开后,启用无线设备", + "description": "When a wifi connection has been disconnected, the stated radio devices are enabled", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToEableOnWwanDisconnect": { + "value": "", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToEableOnWwanDisconnect", + "name[zh_CN]": "Wwan断开后,启用无线设备", + "description": "When a Wwan connection has been disconnected, the stated radio devices are enabled", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToEableOnDock": { + "value": "", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToEableOnDock", + "name[zh_CN]": "停靠后,无线设备被启用", + "description": "After docking the stated radio devices are enabled.", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToDisableOnDock": { + "value": "", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToDisableOnDock", + "name[zh_CN]": "停靠后,无线设备被禁用", + "description": "After docking the stated radio devices are disabled.", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToEableOnUndock": { + "value": "wifi", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToEableOnUndock", + "name[zh_CN]": "解除对接后,启用无线设备", + "description": "After undocking the stated radio devices are enabled.", + "permissions": "readwrite", + "visibility": "private" + }, + "devicesToDisableOnUndock": { + "value": "", + "serial": 0, + "flags": [ + "global" + ], + "name": "DevicesToDisableOnUndock", + "name[zh_CN]": "解除对接后,禁用无线设备", + "description": "After undocking the stated radio devices are disabled.", + "permissions": "readwrite", + "visibility": "private" + }, + "runtimePmOnAc": { + "value": "on", + "serial": 0, + "flags": [ + "global" + ], + "name": "RuntimePmOnAc", + "name[zh_CN]": "PCIe 设备的运行时电源管理", + "description": "Controls runtime power management for PCIe devices.", + "permissions": "readwrite", + "visibility": "public" + }, + "runtimePmOnBat": { + "value": "auto", + "serial": 0, + "flags": [ + "global" + ], + "name": "RuntimePmOnBat", + "name[zh_CN]": "PCIe 设备的运行时电源管理", + "description": "Controls runtime power management for PCIe devices.", + "permissions": "readwrite", + "visibility": "public" + }, + "pcieAspmOnAc": { + "value": "default", + "serial": 0, + "flags": [ + "global" + ], + "name": "PcieAspmOnAc", + "name[zh_CN]": "设置 PCIe ASPM 节能模式", + "description": "Sets PCIe ASPM power saving mode.", + "permissions": "readwrite", + "visibility": "public" + }, + "pcieAspmOnBat": { + "value": "default", + "serial": 0, + "flags": [ + "global" + ], + "name": "PcieAspmOnBat", + "name[zh_CN]": "设置 PCIe ASPM 节能模式", + "description": "Sets PCIe ASPM power saving mode.", + "permissions": "readwrite", + "visibility": "public" + }, + "usbAutosuspend": { + "value": "1", + "serial": 0, + "flags": [ + "global" + ], + "name": "UsbAutosuspend", + "name[zh_CN]": "USB自动挂起", + "description": "Set autosuspend mode for USB devices on boot and when plugged.", + "permissions": "readwrite", + "visibility": "private" + }, + "usbAutosuspendDisableOnShutdown": { + "value": "1", + "serial": 0, + "flags": [ + "global" + ], + "name": "UsbAutosuspendDisableOnShutdown", + "name[zh_CN]": "系统关闭时禁用USB自动挂起", + "description": "Disables USB autosuspend mode upon system shutdown.", + "permissions": "readwrite", + "visibility": "private" + }, + "diskApmLevelOnAc": { + "value": "254 254", + "serial": 0, + "flags": [ + "global" + ], + "name": "DiskApmLevelOnAc", + "name[zh_CN]": "接入电源时磁盘功耗的管理", + "description": "Disk advanced power management level", + "permissions": "readwrite", + "visibility": "public" + }, + "diskApmLevelOnBat": { + "value": "128 128", + "serial": 0, + "flags": [ + "global" + ], + "name": "DiskApmLevelOnBat", + "name[zh_CN]": "接入电池时磁盘功耗的管理", + "description": "Disk advanced power management level", + "permissions": "readwrite", + "visibility": "public" + }, + "sataLinkPwrOnAc": { + "value": "med_power_with_dipm max_performance", + "serial": 0, + "flags": [ + "global" + ], + "name": "SataLinkPwrOnAc", + "name[zh_CN]": "为连接磁盘和光驱的 SATA 链路设置电源管理模式", + "description": "Sets the power management mode for the SATA links connecting disks and optical drives", + "permissions": "readwrite", + "visibility": "public" + }, + "sataLinkPwrOnBat": { + "value": "med_power_with_dipm min_power", + "serial": 0, + "flags": [ + "global" + ], + "name": "SataLinkPwrOnBat", + "name[zh_CN]": "为连接磁盘和光驱的 SATA 链路设置电源管理模式", + "description": "Sets the power management mode for the SATA links connecting disks and optical drives", + "permissions": "readwrite", + "visibility": "public" + } + } +} diff --git a/system/power1/manager.go b/system/power1/manager.go index a40e75eef..448665292 100644 --- a/system/power1/manager.go +++ b/system/power1/manager.go @@ -27,6 +27,12 @@ import ( var noUEvent bool +const ( + dsettingsAppID = "org.deepin.dde.daemon" + dsettingsTlpName = "org.deepin.dde.daemon.power.tlp" + dsettingsBluetoothAdapterName = "org.deepin.dde.daemon.power.bluetoothAdapter" +) + const ( configManagerId = "org.desktopspec.ConfigManager" _configHwSystem = "/usr/share/uos-hw-config" @@ -121,6 +127,10 @@ type Manager struct { // 当前模式 Mode string + // 蓝牙适配器状态 + bluetoothAdapterEnabledCmd string + bluetoothAdapterScanCmd string + // nolint signals *struct { BatteryDisplayUpdate struct { @@ -355,6 +365,17 @@ func (m *Manager) refreshSystemPowerPerformance() { // 获取系统支持的性 } m.systemSigLoop = dbusutil.NewSignalLoop(systemBus, 10) m.initDsgConfig(systemBus) + if err != nil { + logger.Warning(err) + } + err = m.initTlpDsgConfig() + if err != nil { + logger.Warning(err) + } + err = m.initBluetoothAdapterDsgConfig() + if err != nil { + logger.Warning(err) + } m.systemSigLoop.Start() path := m.cpus.getCpuGovernorPath(m.hasPstate) @@ -708,7 +729,10 @@ func (m *Manager) doSetMode(mode string) error { break } - m.setPropPowerSavingModeEnabled(false) + m.PropsMu.Lock() + m.setPowerSavingModeEnabled(false) + m.PropsMu.Unlock() + balanceScalingGovernor := m.balanceScalingGovernor // if do not have pstate, go to the logic below if !m.hasPstate { @@ -749,8 +773,9 @@ func (m *Manager) doSetMode(mode string) error { err = dbusutil.MakeErrorf(m, "PowerMode", "%q mode is not supported", mode) break } - - m.setPropPowerSavingModeEnabled(true) + m.PropsMu.Lock() + m.setPowerSavingModeEnabled(true) + m.PropsMu.Unlock() if m.hasPstate { err = m.doSetCpuGovernor("power") } else { @@ -774,7 +799,9 @@ func (m *Manager) doSetMode(mode string) error { err = dbusutil.MakeErrorf(m, "PowerMode", "%q mode is not supported", mode) break } - m.setPropPowerSavingModeEnabled(false) + m.PropsMu.Lock() + m.setPowerSavingModeEnabled(false) + m.PropsMu.Unlock() err = m.doSetCpuGovernor("performance") if err != nil { logger.Warning(err) @@ -817,3 +844,15 @@ func (m *Manager) doSetCpuGovernor(governor string) error { } return err } + +func (m *Manager) setPowerSavingModeEnabled(enable bool) (changed bool) { + changed = m.setPropPowerSavingModeEnabled(enable) + if !changed { + return + } + err := m.writePowerSavingModeEnabledCbImpl(enable) + if err != nil { + logger.Warning(err) + } + return +} diff --git a/system/power1/manager_bluetoothadapter.go b/system/power1/manager_bluetoothadapter.go new file mode 100644 index 000000000..8c103adf9 --- /dev/null +++ b/system/power1/manager_bluetoothadapter.go @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later +package power +import ( + "os/exec" + "regexp" + "strings" +) + +func getDevices() (devices []string) { + re := regexp.MustCompile(`hci\d+`) + out, err := exec.Command("hciconfig", "-a").CombinedOutput() + if err != nil { + logger.Warning(err) + return + } + var dataLines = strings.Split(string(out), "\n") + if len(dataLines) == 0 { + logger.Warning("there is no device") + return + } + for line := range dataLines { + matches := re.FindStringSubmatch(dataLines[line]) + if len(matches) != 0 { + devices = append(devices, matches[0]) + } + } + return +} +func setHciconfig(cmd string) { + devices := getDevices() + for index := range devices { + _, err := exec.Command("hciconfig", devices[index], cmd).CombinedOutput() + if err != nil { + logger.Warning(err) + } + } +} diff --git a/system/power1/manager_lmt.go b/system/power1/manager_lmt.go deleted file mode 100644 index 87556893e..000000000 --- a/system/power1/manager_lmt.go +++ /dev/null @@ -1,281 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package power - -import ( - "bufio" - "io/ioutil" - "os" - "path/filepath" - "strings" - - dbus "github.com/godbus/dbus/v5" - "github.com/linuxdeepin/go-lib/dbusutil" -) - -// laptop mode tools config file -const lmtConfigFile = "/etc/laptop-mode/laptop-mode.conf" -const laptopModeBin = "/usr/sbin/laptop_mode" - -const ( - lmtConfigAuto = 1 - lmtConfigEnabled = 2 - lmtConfigDisabled = 3 -) - -const lowBatteryThreshold = 20.0 - -func isLaptopModeBinOk() bool { - _, err := os.Stat(laptopModeBin) - return err == nil -} - -func setLMTConfig(mode int) (changed bool, err error) { - lines, err := loadLmtConfig() - if err != nil { - // ignore not exist error - if os.IsNotExist(err) { - return false, nil - } - logger.Warning(err) - return false, err - } - - dict := make(map[string]string) - switch mode { - case lmtConfigAuto: - dict["ENABLE_LAPTOP_MODE_TOOLS"] = "1" - dict["ENABLE_LAPTOP_MODE_ON_BATTERY"] = "1" - dict["ENABLE_LAPTOP_MODE_ON_AC"] = "0" - case lmtConfigEnabled: - dict["ENABLE_LAPTOP_MODE_TOOLS"] = "1" - dict["ENABLE_LAPTOP_MODE_ON_BATTERY"] = "1" - dict["ENABLE_LAPTOP_MODE_ON_AC"] = "1" - case lmtConfigDisabled: - dict["ENABLE_LAPTOP_MODE_TOOLS"] = "1" - dict["ENABLE_LAPTOP_MODE_ON_BATTERY"] = "0" - dict["ENABLE_LAPTOP_MODE_ON_AC"] = "0" - } - lines, changed = modifyLMTConfig(lines, dict) - if changed { - logger.Debug("write LMT Config") - err = writeLmtConfig(lines) - if err != nil { - return false, err - } - } - - return changed, nil -} - -func reloadLaptopModeService() error { - if !isLaptopModeBinOk() { - logger.Debug("laptop mode tools is not installed") - return nil - } - - systemBus, err := dbus.SystemBus() - if err != nil { - return err - } - systemdObj := systemBus.Object("org.freedesktop.systemd1", "/org/freedesktop/systemd1") - return systemdObj.Call("org.freedesktop.systemd1.Manager.ReloadUnit", - dbus.FlagNoAutoStart, "laptop-mode.service", "replace").Err -} - -func modifyLMTConfig(lines []string, dict map[string]string) ([]string, bool) { - var changed bool - for idx := range lines { - line := lines[idx] - for key, value := range dict { - if strings.HasPrefix(line, key) { - newLine := key + "=" + value - if line != newLine { - changed = true - lines[idx] = newLine - } - delete(dict, key) - } - } - if len(dict) == 0 { - break - } - } - if len(dict) > 0 { - for key, value := range dict { - newLine := key + "=" + value - lines = append(lines, newLine) - } - changed = true - } - return lines, changed -} - -func loadLmtConfig() ([]string, error) { - f, err := os.Open(lmtConfigFile) - if err != nil { - return nil, err - } - defer f.Close() - - var lines []string - scanner := bufio.NewScanner(bufio.NewReader(f)) - for scanner.Scan() { - line := scanner.Text() - lines = append(lines, line) - } - if scanner.Err() != nil { - return nil, scanner.Err() - } - - return lines, nil -} - -func writeLmtConfig(lines []string) error { - tempFile, err := writeLmtConfigTemp(lines) - if err != nil { - if tempFile != "" { - os.Remove(tempFile) - } - return err - } - return os.Rename(tempFile, lmtConfigFile) -} - -func writeLmtConfigTemp(lines []string) (string, error) { - dir := filepath.Dir(lmtConfigFile) - err := os.MkdirAll(dir, 0755) - if err != nil { - return "", err - } - - f, err := ioutil.TempFile(dir, "laptop-mode.conf") - logger.Debug("writeLmtConfig temp file", f.Name()) - if err != nil { - return "", err - } - defer f.Close() - err = f.Chmod(0644) - if err != nil { - return f.Name(), err - } - - bufWriter := bufio.NewWriter(f) - for _, line := range lines { - _, err := bufWriter.WriteString(line) - if err != nil { - logger.Warning(err) - } - err = bufWriter.WriteByte('\n') - if err != nil { - logger.Warning(err) - } - } - return f.Name(), bufWriter.Flush() -} - -func (m *Manager) writePowerSavingModeEnabledCb(write *dbusutil.PropertyWrite) *dbus.Error { - logger.Debug("set laptop mode enabled", write.Value) - - enabled := write.Value.(bool) - var err error - var lmtCfgChanged bool - - m.PropsMu.Lock() - m.setPropPowerSavingModeAuto(false) - m.setPropPowerSavingModeAutoWhenBatteryLow(false) - m.PropsMu.Unlock() - - if enabled { - lmtCfgChanged, err = setLMTConfig(lmtConfigEnabled) - } else { - lmtCfgChanged, err = setLMTConfig(lmtConfigDisabled) - } - - if err != nil { - logger.Warning("failed to set LMT config:", err) - } - - if lmtCfgChanged { - err := reloadLaptopModeService() - if err != nil { - logger.Warning(err) - } - } - - return nil -} - -func (m *Manager) updatePowerSavingMode() { // 根据用户设置以及当前状态,修改节能模式 - if !m.initDone { - // 初始化未完成时,暂不提供功能 - return - } - var enable bool - var lmtCfgChanged bool - var err error - if !m.IsPowerSaveSupported { - enable = false - logger.Debug("IsPowerSaveSupported is false.") - } else if m.PowerSavingModeAuto && m.PowerSavingModeAutoWhenBatteryLow { - if m.OnBattery || m.batteryLow { - enable = true - } else { - enable = false - } - } else if m.PowerSavingModeAuto && !m.PowerSavingModeAutoWhenBatteryLow { - if m.OnBattery { - enable = true - } else { - enable = false - } - } else if !m.PowerSavingModeAuto && m.PowerSavingModeAutoWhenBatteryLow { - if m.batteryLow { - enable = true - } else { - enable = false - } - } else { - return // 未开启两个自动节能开关 - } - - if enable { - logger.Debug("auto switch to powersave mode") - err = m.doSetMode("powersave") - } else { - if m.IsBalanceSupported { - logger.Debug("auto switch to balance mode") - err = m.doSetMode("balance") - } - } - - if err != nil { - logger.Warning(err) - } - - logger.Info("updatePowerSavingMode PowerSavingModeEnabled: ", enable) - m.PropsMu.Lock() - changed := m.setPropPowerSavingModeEnabled(enable) - m.PropsMu.Unlock() - if changed { - if enable { - lmtCfgChanged, err = setLMTConfig(lmtConfigEnabled) - if err != nil { - logger.Warning("failed to set LMT config:", err) - } - } else { - lmtCfgChanged, err = setLMTConfig(lmtConfigDisabled) - if err != nil { - logger.Warning("failed to set LMT config:", err) - } - } - if lmtCfgChanged { - err := reloadLaptopModeService() - if err != nil { - logger.Warning(err) - } - } - } -} diff --git a/system/power1/manager_powersave.go b/system/power1/manager_powersave.go new file mode 100644 index 000000000..92fd1d098 --- /dev/null +++ b/system/power1/manager_powersave.go @@ -0,0 +1,234 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power + +import ( + "errors" + "github.com/godbus/dbus/v5" + configmanager "github.com/linuxdeepin/go-dbus-factory/org.desktopspec.ConfigManager" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (m *Manager) initTlpDsgConfig() error { + if !isTlpBinOk() { + return errors.New("tlp is not installed") + } + logger.Info("initTlpDsgConfig.") + // dsg 配置 + var keyMap = map[string]string{ + // 音频 + "soundPowerSaveOnAc": "SOUND_POWER_SAVE_ON_AC", // 0/1 + "soundPowerSaveOnBat": "SOUND_POWER_SAVE_ON_BAT", // 0/1 + "soundPowerSaveController": "SOUND_POWER_SAVE_CONTROLLER", // Y/N + // 电池 + "startChargeThreshBatPrimary": "START_CHARGE_THRESH_BAT0", // values in % + "stopChargeThreshBatPrimary": "STOP_CHARGE_THRESH_BAT0", // values in % + "startChargeThreshBatSecondary": "START_CHARGE_THRESH_BAT1", // values in % + "stopChargeThreshBatSecondary": "STOP_CHARGE_THRESH_BAT1", // values in % + "restoreThresholdsOnBat": "RESTORE_THRESHOLDS_ON_BAT", // values in % + // 驱动器槽 + "bayPoweroffOnAc": "BAY_POWEROFF_ON_AC", // 0/1 + "bayPoweroffOnBat": "BAY_POWEROFF_ON_BAT", // 0/1 + "bayDevice": "BAY_DEVICE", // Default when unconfigured: sr0 + // 磁盘 + "maxLostWorkSecsOnAc": "MAX_LOST_WORK_SECS_ON_AC", // Timeout (in seconds) + "maxLostWorkSecsOnBat": "MAX_LOST_WORK_SECS_ON_BAT", // Timeout (in seconds) + // 内核 + "nmiWatchdog": "NMI_WATCHDOG", // 0/1 + // 网络 + "wifiPwrOnAc": "WIFI_PWR_ON_AC", // of/on + "wifiPwrOnBat": "WIFI_PWR_ON_BAT", // of/on + "wolDisable": "WOL_DISABLE", // Y/N + // 无线设备 + "restoreDeviceStateOnStartup": "RESTORE_DEVICE_STATE_ON_STARTUP", // 0/1 + "devicesToDisableOnStartup": "DEVICES_TO_DISABLE_ON_STARTUP", // bluetooth/wifi/wwan (Multiple devices are separated with blanks) + "devicesToEableOnStartup": "DEVICES_TO_ENABLE_ON_STARTUP", // as above + "devicesToDisableOnShutdown": "DEVICES_TO_DISABLE_ON_SHUTDOWN", // as above + "devicesToEableOnShutdown": "DEVICES_TO_ENABLE_ON_SHUTDOWN", // as above + "devicesToEableOnAc": "DEVICES_TO_ENABLE_ON_AC", // as above + "devicesToDisableOnBat": "DEVICES_TO_DISABLE_ON_BAT", // as above + "devicesToDisableOnBatNotInUse": "DEVICES_TO_DISABLE_ON_BAT_NOT_IN_USE", // as above + "devicesToDisableOnLanConnect": "DEVICES_TO_DISABLE_ON_LAN_CONNECT", // as above + "devicesToDisableOnWifiConnect": "DEVICES_TO_DISABLE_ON_WIFI_CONNECT", // as above + "devicesToDisableOnWwanConnect": "DEVICES_TO_DISABLE_ON_WWAN_CONNECT", // as above + "devicesToEableOnLanDisconnect": "DEVICES_TO_ENABLE_ON_LAN_DISCONNECT", // as above + "devicesToEableOnWifiDisconnect": "DEVICES_TO_ENABLE_ON_WIFI_DISCONNECT", // as above + "devicesToEableOnWwanDisconnect": "DEVICES_TO_ENABLE_ON_WWAN_DISCONNECT", // as above + "devicesToEableOnDock": "DEVICES_TO_ENABLE_ON_DOCK", // as above + "devicesToDisableOnDock": "DEVICES_TO_DISABLE_ON_DOCK", // as above + "devicesToEableOnUndock": "DEVICES_TO_ENABLE_ON_UNDOCK", // as above + "devicesToDisableOnUndock": "DEVICES_TO_DISABLE_ON_UNDOCK", // as above + // 运行时电源管理 + "runtimePmOnAc": "RUNTIME_PM_ON_AC", // on/auto + "runtimePmOnBat": "RUNTIME_PM_ON_BAT", // on/auto + "pcieAspmOnAc": "PCIE_ASPM_ON_AC", // default/performance/powersave/powersupersave + "pcieAspmOnBat": "PCIE_ASPM_ON_BAT", // default/performance/powersave/powersupersave + // USB + "usbAutosuspend": "USB_AUTOSUSPEND", // 0/1 + "usbAutosuspendDisableOnShutdown": "USB_AUTOSUSPEND_DISABLE_ON_SHUTDOWN", // 0/1 + // 硬盘 + "diskApmLevelOnAc": "DISK_APM_LEVEL_ON_AC", // default:"254 254" + "diskApmLevelOnBat": "DISK_APM_LEVEL_ON_BAT", // default:"128 128" + "sataLinkPwrOnAc": "SATA_LINKPWR_ON_AC", // default:"med_power_with_dipm max_performance" + "sataLinkPwrOnBat": "SATA_LINKPWR_ON_BAT", // default:"med_power_with_dipm min_power" + } + + ds := configmanager.NewConfigManager(m.systemSigLoop.Conn()) + dsTlpPath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsTlpName, "") + if err != nil { + return err + } + dsTlp, err := configmanager.NewManager(m.systemSigLoop.Conn(), dsTlpPath) + if err != nil { + return err + } + + getTlpChangedVal := func(key string) (val string) { + data, err := dsTlp.Value(0, key) + if err != nil { + logger.Warning(err) + return + } + + return data.Value().(string) + } + + dsTlp.InitSignalExt(m.systemSigLoop, true) + dsTlp.ConnectValueChanged(func(key string) { + logger.Info("DSG org.deepin.dde.daemon.tlp valueChanged, key : ", key) + setTlpConfig(keyMap[key], getTlpChangedVal(key)) + }) + + return err +} + +func (m *Manager) initBluetoothAdapterDsgConfig() error { + logger.Info("initBluetoothAdapterDsgConfig.") + ds := configmanager.NewConfigManager(m.systemSigLoop.Conn()) + dsBluetoothAdapterPath, err := ds.AcquireManager(0, dsettingsAppID, dsettingsBluetoothAdapterName, "") + if err != nil { + return err + } + dsBluetoothAdapter, err := configmanager.NewManager(m.systemSigLoop.Conn(), dsBluetoothAdapterPath) + if err != nil { + return err + } + + getBluetoothAdapterChangedVal := func(key string) (val string) { + data, err := dsBluetoothAdapter.Value(0, key) + if err != nil { + logger.Warning(err) + return + } + + return data.Value().(string) + } + + dsBluetoothAdapter.InitSignalExt(m.systemSigLoop, true) + dsBluetoothAdapter.ConnectValueChanged(func(key string) { + logger.Info("DSG org.deepin.dde.daemon.bluetoothAdapter valueChanged, key : ", key) + go setHciconfig(getBluetoothAdapterChangedVal(key)) + m.bluetoothAdapterEnabledCmd = getBluetoothAdapterChangedVal("enableDevices") + m.bluetoothAdapterScanCmd = getBluetoothAdapterChangedVal("scanDevices") + }) + + m.bluetoothAdapterEnabledCmd = getBluetoothAdapterChangedVal("enableDevices") + m.bluetoothAdapterScanCmd = getBluetoothAdapterChangedVal("scanDevices") + + return err +} + +func (m *Manager) updatePowerSavingMode() { // 根据用户设置以及当前状态,修改节能模式 + if !m.initDone { + // 初始化未完成时,暂不提供功能 + return + } + var enable bool + + var err error + if !m.IsPowerSaveSupported { + enable = false + logger.Debug("IsPowerSaveSupported is false.") + } else if m.PowerSavingModeAuto && m.PowerSavingModeAutoWhenBatteryLow { + if m.OnBattery || m.batteryLow { + enable = true + } else { + enable = false + } + } else if m.PowerSavingModeAuto && !m.PowerSavingModeAutoWhenBatteryLow { + if m.OnBattery { + enable = true + } else { + enable = false + } + } else if !m.PowerSavingModeAuto && m.PowerSavingModeAutoWhenBatteryLow { + if m.batteryLow { + enable = true + } else { + enable = false + } + } else { + return // 未开启两个自动节能开关 + } + + if enable { + logger.Debug("auto switch to powersave mode") + err = m.doSetMode("powersave") + } else { + if m.IsBalanceSupported { + logger.Debug("auto switch to balance mode") + err = m.doSetMode("balance") + } + } + + if err != nil { + logger.Warning(err) + } + + logger.Info("updatePowerSavingMode PowerSavingModeEnabled: ", enable) + m.PropsMu.Lock() + m.setPowerSavingModeEnabled(enable) + m.PropsMu.Unlock() +} + +func (m *Manager) writePowerSavingModeEnabledCb(write *dbusutil.PropertyWrite) *dbus.Error { + logger.Info("set tlp enabled", write.Value) + return dbusutil.ToError(m.writePowerSavingModeEnabledCbImpl(write.Value.(bool))) +} + +func (m *Manager) writePowerSavingModeEnabledCbImpl(enabled bool) error { + var err error + var tlpCfgChanged bool + bluetoothAdapterEnabledCmd := "up" + bluetoothAdapterScanCmd := "piscan" + + m.setPropPowerSavingModeEnabled(enabled) + + if enabled { + tlpCfgChanged, err = setTlpConfigMode(tlpConfigEnabled) + bluetoothAdapterEnabledCmd = m.bluetoothAdapterEnabledCmd + bluetoothAdapterScanCmd = m.bluetoothAdapterScanCmd + } else { + tlpCfgChanged, err = setTlpConfigMode(tlpConfigDisabled) + } + + go func() { + setHciconfig(bluetoothAdapterEnabledCmd) + setHciconfig(bluetoothAdapterScanCmd) + }() + + if err != nil { + logger.Warning("failed to set tlp config:", err) + } + + if tlpCfgChanged { + err := reloadTlpService() + if err != nil { + logger.Warning(err) + } + } + + return nil +} diff --git a/system/power1/manager_tlp.go b/system/power1/manager_tlp.go new file mode 100644 index 000000000..0ee937377 --- /dev/null +++ b/system/power1/manager_tlp.go @@ -0,0 +1,220 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package power + +import ( + "bufio" + "errors" + "github.com/godbus/dbus/v5" + systemd1 "github.com/linuxdeepin/go-dbus-factory/system/org.freedesktop.systemd1" + "github.com/linuxdeepin/go-lib/utils" + "os" + "os/exec" + "path/filepath" + "strings" +) + +const lowBatteryThreshold = 20.0 + +// tlp config file +const tlpConfigFile = "/etc/tlp.d/50-tlp.conf" +const tlpConfigFileOder = "/etc/default/tlp" +const tlpBin = "/usr/sbin/tlp" + +const ( + tlpConfigAuto = 1 + tlpConfigEnabled = 2 + tlpConfigDisabled = 3 +) + +func isTlpBinOk() bool { + _, err := exec.LookPath("tlp") + if err == nil { + return true + } + return utils.IsFileExist(tlpBin) +} + +func setTlpConfig(key string, val string) { + path := tlpConfigPath() + lines, err := loadTlpConfig(path) + if err != nil { + logger.Warning(err) + return + } + + dict := make(map[string]string) + dict[key] = val + lines, changed := modifyTlpConfig(lines, dict) + if changed { + logger.Debug("write tlp Config") + err = writeTlpConfig(lines, path) + if err != nil { + logger.Warning(err) + } + } +} + +func setTlpConfigMode(mode int) (changed bool, err error) { + path := tlpConfigPath() + lines, err := loadTlpConfig(path) + if err != nil { + logger.Warning(err) + // ignore not exist error + if os.IsNotExist(err) { + return false, nil + } + return false, err + } + + dict := make(map[string]string) + switch mode { + case tlpConfigAuto: + dict["TLP_ENABLE"] = "1" + dict["TLP_PERSISTENT_DEFAULT"] = "0" + case tlpConfigEnabled: + dict["TLP_ENABLE"] = "1" + dict["TLP_DEFAULT_MODE"] = "BAT" + dict["TLP_PERSISTENT_DEFAULT"] = "1" + case tlpConfigDisabled: + dict["TLP_ENABLE"] = "1" + dict["TLP_DEFAULT_MODE"] = "AC" + dict["TLP_PERSISTENT_DEFAULT"] = "1" + } + lines, changed = modifyTlpConfig(lines, dict) + if changed { + logger.Debug("write tlp Config") + err = writeTlpConfig(lines, path) + if err != nil { + return false, err + } + } + + return changed, nil +} + +func reloadTlpService() error { + if !isTlpBinOk() { + return errors.New("tlp is not installed") + } + + systemBus, err := dbus.SystemBus() + if err != nil { + return err + } + sysManager := systemd1.NewManager(systemBus) + _, err = sysManager.ReloadUnit(dbus.FlagNoAutoStart, "tlp.service", "replace") + return err +} + +func modifyTlpConfig(lines []string, dict map[string]string) ([]string, bool) { + var changed bool + for idx := range lines { + line := lines[idx] + line = strings.TrimPrefix(line, "#") + for key, value := range dict { + if strings.HasPrefix(line, key) { + newLine := key + "=" + value + if line != newLine { + changed = true + lines[idx] = newLine + } + delete(dict, key) + } + } + if len(dict) == 0 { + break + } + } + if len(dict) > 0 { + for key, value := range dict { + newLine := key + "=" + value + lines = append(lines, newLine) + } + changed = true + } + return lines, changed +} + +func tlpConfigPath() (configFile string) { + if !isTlpBinOk() { + logger.Warning("tlp is not installed") + return + } + if utils.IsFileExist(tlpConfigFileOder) { + return tlpConfigFileOder + } else { + return tlpConfigFile + } +} + +func loadTlpConfig(path string) ([]string, error) { + f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644) + defer f.Close() + if err != nil { + return nil, err + } + + var lines []string + scanner := bufio.NewScanner(bufio.NewReader(f)) + for scanner.Scan() { + line := scanner.Text() + lines = append(lines, line) + } + if scanner.Err() != nil { + return nil, scanner.Err() + } + + if len(lines) == 0 { + lines = append(lines, "# Generate by dde-system-daemon") + } + + return lines, nil +} + +func writeTlpConfig(lines []string, path string) error { + tempFile, err := writeTlpConfigTemp(lines, path) + if err != nil { + if tempFile != "" { + os.Remove(tempFile) + } + return err + } + return os.Rename(tempFile, path) +} + +func writeTlpConfigTemp(lines []string, path string) (string, error) { + dir := filepath.Dir(path) + err := os.MkdirAll(dir, 0755) + if err != nil { + return "", err + } + + f, err := os.CreateTemp(dir, "tlp.conf") + + defer f.Close() + logger.Debug("writeTlpConfig temp file", f.Name()) + if err != nil { + return "", err + } + + err = f.Chmod(0644) + if err != nil { + return f.Name(), err + } + + bufWriter := bufio.NewWriter(f) + for _, line := range lines { + _, err := bufWriter.WriteString(line) + if err != nil { + logger.Warning(err) + } + err = bufWriter.WriteByte('\n') + if err != nil { + logger.Warning(err) + } + } + return f.Name(), bufWriter.Flush() +}