linux电源管理
十月 18, 2025 更新: 八月 16, 2026 [Linux 与系统] #pm查看suspend休眠配置模式
cat /sys/power/mem_sleep
echo deep | sudo tee /sys/power/mem_sleep
配置hibernate休眠
cat /etc/fstab
swapon --show
sudo swapoff -a
sudo dd if=/dev/zero of=/swapfile bs=1G count=17
sudo swapon /swapfile
# 获取swap文件的offset
sudo filefrag -v /swapfile | awk '{if($1=="0:") print $4}'
# 查看根分区 UUID
findmnt -no UUID -T /
sudo vim /etc/default/grub
# GRUB_CMDLINE_LINUX_DEFAULT="quiet splash mem_sleep_default=deep resume=UUID=<磁盘分区UUID> resume_offset=<swap文件偏移量>"
sudo update-grub
配置电源管理
cat <<EOF > /etc/systemd/sleep.conf.d/enable-sleep.conf
AllowSuspend=yes
AllowHibernation=yes
HibernateMode=platform shutdown
HibernateState=disk
AllowSuspendThenHibernate=yes
AllowHybridSleep=yes
SuspendState=mem standby freeze
EOF
sudo mkdir /etc/systemd/logind.conf.d
cat <<EOF | sudo tee /etc/systemd/logind.conf.d/override.conf
[Login]
HandlePowerKey=suspend-then-hibernate
HandleRebootKey=reboot
HandleRebootKeyLongPress=poweroff
HandleSuspendKey=suspend
HandleSuspendKeyLongPress=hibernate
IdleAction=suspend-then-hibernate
IdleActionSec=30min
EOF
systemd-analyze cat-config systemd/sleep.conf
systemd-analyze cat-config systemd/logind.conf
防休眠(让机器随时可连)
场景:远程机(笔记本、服务器)需要 7x24 可 SSH 连接,不能自动睡。
方案一:mask 休眠目标(简单粗暴)
# 屏蔽所有休眠途径:空闲挂起、合盖、电源键、手动 suspend 全部失效
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target suspend-then-hibernate.target
# 验证(显示 masked)
systemctl list-units --type=target --all | grep -Ei "suspend|sleep|hibernate"
# 恢复
sudo systemctl unmask sleep.target suspend.target hibernate.target hybrid-sleep.target suspend-then-hibernate.target
缺点(太重):手动 systemctl suspend、按电源键、合盖全部静默失败;电池模式下也无法省电;无法区分 AC/电池策略。
方案二:GNOME 电源管理(推荐,粒度细)
原理:gsd-power 持有 sleep block 抑制剂(systemd-inhibit --list 可查),logind 执行 IdleAction 时被抑制剂挡住,机器不会因空闲挂起,但手动挂起/电源键仍然可用。
# 空闲自动挂起:AC/电池 均设为 nothing(不挂起)
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type nothing
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-type nothing
gsettings get org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type # 验证
合盖行为:logind drop-in 必须带 [Login] 段头(易踩坑)
症状:/etc/systemd/logind.conf.d/override.conf 写了 HandleLidSwitch=ignore,systemd-analyze cat-config 也显示已合并,但 logind 生效值仍是 suspend,合盖照样挂起。
根因:drop-in 文件漏了 [Login] 段头——systemd 配置解析要求键必须属于某个 section,没有段头整行被忽略。日志可见(需 root 读 journal):
systemd-logind: /etc/systemd/logind.conf.d/override.conf:1: Assignment outside of section. Ignoring.
systemd-analyze cat-config 只拼接文件内容、不做 section 校验,所以看起来一切正常——别被它骗了。
(旧版曾误判为"gsd-power 在会话启动时用 SetLidSwitchBehavior 覆盖 logind 配置":实际 systemd ≥257 已移除该方法,logind 合盖行为完全由配置决定,不存在运行时覆盖;D-Bus 监听也证实无任何调用。误判源于对 HandleLidSwitch 属性值的错误解读——它如实反映配置,配置只是没生效而已。)
排查/验证:
# 看 logind 当前生效的合盖行为
busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager HandleLidSwitch
# drop-in 未生效时,root 查看被忽略的原因
sudo journalctl -u systemd-logind -n 20 | grep -i "outside of section"
修复(改完 systemctl restart systemd-logind 立即生效;会登出图形会话,对纯服务器无影响):
sudo tee /etc/systemd/logind.conf.d/override.conf <<'EOF'
[Login]
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
EOF
sudo systemctl restart systemd-logind
合盖 ignore 之后:屏幕不会自动息屏(省电确认方法)
合盖不挂起后,OS 层面对 lid 事件不再做任何动作,屏幕也不会自动熄灭:背光保持原亮度、GPU 继续渲染、eDP 供电不断。是否真省电取决于笔记本 EC 固件是否在硬件层切断面板供电(系统内无法直接确认,多数笔记本 EC 会断,但别默认)。
确认屏幕当前是否在省电状态:
# 背光设定值(0 = 软件层已熄屏;非 0 = 还亮着)
cat /sys/class/backlight/*/actual_brightness /sys/class/backlight/*/max_brightness
# GPU 渲染管道是否还活动(有 "1920x1080" 这样的帧缓冲 = 还在渲染)
sudo cat /sys/kernel/debug/dri/0/state | grep "crtc-pos"
# eDP 数据通道供电(PORT_DDI_LANES_A = 1 说明还在供电)
sudo cat /sys/kernel/debug/dri/0/i915_power_domain_info | grep "PORT_DDI_LANES_A"
# 功耗对比(最可靠;需拔电源用电池,合盖前后各读一次)
awk '{print "放电功率(W):", $1*$2/1e12}' \
/sys/class/power_supply/BAT1/current_now /sys/class/power_supply/BAT1/voltage_now
# 或者最直接:开一条缝看屏幕
真正省电靠 idle 息屏:GNOME org.gnome.desktop.session idle-delay(默认 300s)闲置后屏幕熄灭(背光归 0),与合盖无关;0 = 永不自动息屏。注意登录页(gdm greeter)状态下的息屏由 greeter 决定,未必生效——要确保息屏先登录回图形会话。合盖 ignore 不影响手动 systemctl suspend(需要时仍可手动挂起省电)。
SSH 会话里 gsettings get/set 直接可用(dconf 写用户库,无需会话 DBus);但 gdbus/busctl 调图形会话接口(息屏/锁屏,见下文)需借用图形会话的 DBus(DBUS_SESSION_BUS_ADDRESS 从 gnome-shell 进程 environ 取)。
排查:远程机 SSH 断连
场景症状 ssh: connect to host ... No route to host,先分清是「机器挂了」还是「换 IP 了」:
ping -c2 <host> # 不通:机器挂起/关机,或 IP 已变
uptime -p; last reboot -2 # suspend 不重置 uptime;last reboot 区分挂起 vs 重启
cat /proc/acpi/button/lid/*/state # 合盖挂起的机器:开盖自动恢复(SSH 又通了就是合盖挂起)
nmap -sn -T4 192.168.2.0/24 | grep report # IP 变了:扫存活主机,用 hostname 对上目标
/etc/hosts 静态条目过期是常见原因(机器在线但换 DHCP IP)。
排查方法论(合盖挂起实战教训)
- 认错机器:主机离线时 nmap 扫到活机,先核对
hostname、cat /sys/class/dmi/id/product_name、系统版本再当目标——局域网可能有多台相似机器(本案例把 .147 的 H3C MegaBook 当成 .63 的华为 MateBook 配置了一下午,改错了对象)。 - journal 组权限坑:非 root 且不在
adm/systemd-journal组时,journalctl只显示本人会话的消息,系统消息(logind 等)全被隐藏——grep 不到 ≠ 没有日志。排查 systemd 行为一律sudo journalctl -u <unit> -n 20。本案例 drop-in 被忽略的Assignment outside of section警告就是加了 sudo 才看到的。 - 抓 D-Bus 调用方:
dbus-monitor --system "type=method_call,member=<方法名>"(非 root 自动降级 eavesdropping,仍能抓到),配合重启服务/登录会话重现。本案例用监听证实没有任何会话进程调用 SetLidSwitchBehavior,排除"运行时覆盖"理论,把排查收敛到配置解析本身。 - systemd ≥257 已移除 SetLidSwitchBehavior:logind 合盖行为完全由配置决定,不存在运行时覆盖——配置"没生效"优先怀疑配置本身(段头/文件路径/优先级),而不是被谁覆盖。
Wi-Fi 不断线
笔记本掉线头号元凶是 Wi-Fi 省电(NIC 间歇性休眠),SSH 空闲断连则是 NAT 超时掐线:
# 关闭 Wi-Fi 省电(全局 + 单个连接,重启后仍生效)
sudo nmcli g s wifi.powersave 2
sudo nmcli con mod "SSID" 802-11-wireless.powersave disable
sudo nmcli con down "SSID" && sudo nmcli con up "SSID" # 重连使连接级配置生效
sudo iw dev wlan0 get power_save # 验证:Power save: off
# sshd 保活:/etc/ssh/sshd_config.d/keepalive.conf
ClientAliveInterval 60
ClientAliveCountMax 3
sudo systemctl restart ssh
息屏与锁屏
息屏(DPMS)与休眠独立:息屏只是屏幕进省电状态,系统照常运行、SSH 不掉线;休眠是整机冻结。
# 检查/关闭自动息屏(GNOME)
gsettings get org.gnome.desktop.session idle-delay # 秒;0 = 永不自动息屏
gsettings set org.gnome.desktop.session idle-delay 0
gsettings get org.gnome.settings-daemon.plugins.power idle-dim # 息屏前先变暗
远程控制息屏/亮屏(即时动作;gsettings 只改"空闲多久自动息屏"之类的规则,不是动作,不能替代):
# GNOME Wayland:SSH 会话需借用图形会话的 bus。
# systemd 用户会话有固定路径 /run/user/<uid>/bus,比从 gnome-shell environ 里挖更稳;
# 跨用户会话(如活动会话是 gdm greeter,属 Debian-gdm)用 sudo -u。
busctl --user call org.gnome.ScreenSaver /org/gnome/ScreenSaver org.gnome.ScreenSaver SetActive b true # true=息屏, false=亮屏
busctl --user call org.gnome.ScreenSaver /org/gnome/ScreenSaver org.gnome.ScreenSaver GetActive # 查询屏保状态
# GNOME 同时实现了 org.gnome.ScreenSaver 和 org.freedesktop.ScreenSaver 两个名字(实测都可用),
# 用哪个都行;busctl 比 gdbus 稳(本机实测 gdbus 传 b 类型参数报 "expected value" 解析错误)
坑与边界(实测):
- greeter 登录页没有 ScreenSaver 服务(greeter 的 bus 上只有 keyring)——上述 D-Bus 方案、
xdg-screensaver、gnome-screensaver-command在登录页全部失效 - 兜底方案:直接写背光 sysfs(
/sys/class/backlight/intel_backlight/brightness,0 = 息屏),greeter/用户会话都适用;亮屏恢复上次值 gnome-screensaver-command已废弃(现代 GNOME 不安装);xdg-screensaver activate实测 exit 0 可用(内部转发到 D-Bus),但同样依赖会话里的 ScreenSaver 服务- 现成脚本(dotfiles
~/.my_local/bin/,随仓库部署,SSH 远程直接可用):screen-state.sh(状态:背光 + 会话屏保)、screen-set.sh off|on(优先 ScreenSaver,无服务时背光兜底,自动定位活动会话并 sudo -u)
# X11 环境有直接工具:xset dpms force off / on
# (旧文曾写 "Wayland 下 xdg-screensaver 已失效"——实测不准:xdg-screensaver 在 Wayland 可用,
# 失效的只是 xset,它只能操作 Xwayland 窗口,点不亮物理屏幕;wlopm 是 wlroots/Sway 系,GNOME 用不了)
# 锁屏:loginctl lock-session <id>(亮屏需密码,不适合远程)
# 锁屏不会断 Wi-Fi(网络栈与显示会话无关);真正断网的是休眠