Power management (简体中文) - ArchWiki

# Power management (简体中文)

systemd 能够处理某些电源相关的 ACPI 事件，通过 `/etc/systemd/logind.conf` 的下列选项配置：

- `HandlePowerKey`：按下电源键后的动作
- `HandleSleepKey`：按下挂起键后的动作
- `HandleHibernateKey`: 按下休眠键后的动作
- `HandleLidSwitch`：合上笔记本盖后待机

动作可以是 `ignore`、`poweroff`、`reboot`、`halt`、`suspend`、`hibernate`、`hybrid-sleep`、`lock` 或 `kexec`。

系统默认设置为:

    HandlePowerKey=poweroff
    HandleSuspendKey=suspend
    HandleHibernateKey=hibernate
    HandleLidSwitch=suspend

不用图形界面、或者使用 i3、awesome 这样简单的桌面管理器时，systemd 可以替代 acpid 处理 ACPI 事件。

注意: 运行 `systemctl restart systemd-logind`，使上述更改立即生效。
注意: systemd 无法处理交流电源和电池 ACPI 事件，所以还得使用 Laptop Mode Tools 或 acpid 工具。

在当前版本的 systemd 中，这些 `Handle` 选项将会被应用到整个系统当中，除非它们被别的程序——例如某个桌面环境中的电源管理器——给“阻止”（inhibited）。如果其它的程序没有阻止这些 `Handle` ，你可能会先被 systemd 挂起你的系统，然后当系统被唤醒之后，电源管理器又会再次将系统挂起。

警告: 目前只有GNOME 和 KDE 支持 "inhibited" 命令。在其它的桌面管理器同样实现该功能之前，如果你想使用Xfce、acpid 或者其它程序来管理 ACPI 事件，你需要把 `Handle` 选项设置为 `ignore`。
注意: 除了内核默认的待机支持后端（用于处理待机/休眠），systemd 也可以使用其他后端（比如 Uswsusp 或 TuxOnIce）。

要令 `systemctl hibernate` 工作，需要按照休眠和 mkinitcpio 唤醒扩展的设置步骤进行操作。（不必安装 `pm-utils`）

#### 休眠时执行的脚本

使用 `systemctl suspend`、`systemctl hibernate` 或 `systemctl hybrid-sleep` 命令执行待机/休眠时，systemd 不会调用 pm-utils。pm-utils 的钩子扩展（hook）——包括 自定义钩子——会失效。不过，systemd 提供了两种类似的待机/休眠时执行脚本的机制。

##### 使用服务文件

可以将服务文件附在 suspend.target、hibernate.target 或 sleep.target 中，这样就能在待机/休眠前后执行某些操作。用户级操作和root/系统级操作应该使用不同的服务文件。要启用用户级服务文件，使用 `# systemctl enable suspend@<用户名> && systemctl enable resume@<用户名>`。例如：

    /etc/systemd/system/suspend@.service

    [Unit]
    Description=User suspend actions
    Before=sleep.target

    [Service]
    User=%I
    Type=forking
    Environment=DISPLAY=:0
    ExecStartPre= -/usr/bin/pkill -u %u unison ; /usr/local/bin/music.sh stop ; /usr/bin/mysql -e 'slave stop'
    ExecStart=/usr/bin/sflock

    [Install]
    WantedBy=sleep.target

    /etc/systemd/system/resume@.service

    [Unit]
    Description=User resume actions
    After=suspend.target

    [Service]
    User=%I
    Type=simple
    ExecStartPre=/usr/local/bin/ssh-connect.sh
    ExecStart=/usr/bin/mysql -e 'slave start'

    [Install]
    WantedBy=suspend.target

至于root/系统级服务（使用 `# systemctl enable root-suspend` 激活）：

    /etc/systemd/system/root-resume.service

    [Unit]
    Description=Local system resume actions
    After=suspend.target

    [Service]
    Type=simple
    ExecStart=/usr/bin/systemctl restart mnt-media.automount

    [Install]
    WantedBy=suspend.target

    /etc/systemd/system/root-suspend.service

    [Unit]
    Description=Local system suspend actions
    Before=sleep.target

    [Service]
    Type=simple
    ExecStart=-/usr/bin/pkill sshfs

    [Install]
    WantedBy=sleep.target

上述服务文件的一些解释（详见 `man systemd.service`）：

- 如果设置 `Type=OneShot`，那么可以使用多个 `ExecStart=` 参数。否则只能写一个，替代方案是在 `ExecStartPre` 中添加命令，或使用分号分隔不同命令（见第一个例子，分号前后的空格都是必须的）。
- 若命令前加上一个“-”（半角减号），则命令返回非零值时会被忽略、当作正常执行处理。
- 有关调试，最好的方法是用 `journalctl` 查看日志。

##### 合并待机和唤醒服务文件

利用下面这种自定义的一体化待机和唤醒服务，使用单一的钩子扩展即可对不同操作（待机/休眠/混合休眠）的不同阶段（进入/唤醒）进行控制。

例子和解释：

    /etc/systemd/system/wicd-sleep.service

    [Unit]
    Description=Wicd sleep hook
    Before=sleep.target
    StopWhenUnneeded=yes

    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=-/usr/share/wicd/daemon/suspend.py
    ExecStop=-/usr/share/wicd/daemon/autoconnect.py

    [Install]
    WantedBy=sleep.target

- `RemainAfterExit=yes`：服务启动后，除非显式地停止，否则就认为是活动的。
- `StopWhenUnneeded=yes`：服务活动时，如果无其他服务依赖该服务，就停止它。在本例中，该服务会在 sleep.target 停止后停止活动。
- 由于 sleep.target 会被 suspend.target、hibernate.target、hybrid-sleep.target 调用，且 sleep.target 本身设置了 StopWhenUnneeded，该服务文件对以上各种操作都是有效的。

##### 使用 /usr/lib/systemd/system-sleep

systemd 在待机/休眠时执行 `/usr/lib/systemd/system-sleep/` 里的所有脚本，传递下面两个参数：

- 参数1：若是准备进入待机/休眠状态，则为 `pre`；唤醒时为 `post`。
- 参数2：事件名称，`suspend`，`hibernate` 或 `hybrid-sleep`。

systemd 会同时执行所有脚本，而不是像 pm-utils 那样顺序执行。

脚本输出会记录在相关服务（`systemd-suspend.service`、`systemd-hibernate.service` 或 `systemd-hybrid-sleep.service`）中。通过日志查看：

    # journalctl -b -u systemd-suspend

注意: 除了使用自定义脚本，还可以利用 `sleep.target`、`suspend.target`、`hibernate.target` 或 `hybrid-sleep.target` 来为单元（unit）添加睡眠状态策略。

脚本示范：

    /usr/lib/systemd/system-sleep/example.sh

    #!/bin/sh
    case $1/$2 in
      pre/*)
        echo "进入 $2 状态..."
        ;;
      post/*)
        echo "从 $2 状态唤醒..."
        ;;
    esac

记得添加可执行权限：

1. chmod a+x /usr/lib/systemd/system-sleep/example.sh

详情参见 `man 7 systemd.special` 和 `man 8 systemd-sleep`。

Category:

- Power management (简体中文)