endaaman.com

2026-02-21

Tips

KDE PlasmaでノートPCのリッド開閉によるhibernateが動かない

Dell XPS 13 9305にArch Linux + KDE Plasma (Wayland) という環境で、ラップトップの蓋を閉じたときにhibernateする設定がうまく動かなかった話。systemctl hibernate は問題なく動くのに、蓋を閉じたときだけ失敗するという状況だった。

やりたいことは以下の通り。

状態 リッド閉じたら
バッテリー 即hibernate
AC電源 suspend → 一定時間後にhibernate

PowerDevil(Plasma標準の電源管理)でうまくいかない

KDE Plasmaでは電源管理をPowerDevilというデーモンが担当しており、systemd-logindのリッドスイッチ処理をblockモードのinhibitorで横取りしている。

$ systemd-inhibit --list
WHO            PID  WHAT                 WHY                      MODE
PowerDevil     1271 handle-lid-switch    KDE handles power events block

Plasmaのシステム設定で「蓋を閉じたときの動作」を変更すると、~/.config/powerdevilrcに反映される。

[Battery][SuspendAndShutdown]
LidAction=2
SleepMode=3

設定自体は正しく保存されているが、蓋を閉じると失敗のループに入る。

$ journalctl -b -t systemd-logind
Lid closed.
The system will hibernate now!
Operation 'hibernate' finished.    ← 数秒で終わる = 失敗
The system will hibernate now!     ← リトライ
Operation 'hibernate' finished.    ← また失敗
...(蓋を開けるまで繰り返し)
Lid opened.

正常なhibernateは1分ほどかかるのに対して、数秒で「完了」しているので明らかに失敗している。

原因: PowerDevilのwakeupsourcehelper

蓋を閉じた瞬間のjournalを見ると、PowerDevilがhibernate要求と並行してwakeupsourcehelperというヘルパープロセスを起動している。

16:51:43 Lid closed.
16:51:43 Started [email protected]
16:51:43 The system will hibernate now!

wakeupsourcehelperはsuspend中のスプリアスウェイクアップを防ぐために/sys/power/wakeup_countを読み書きするroot権限のヘルパーである。このヘルパーがhibernateのfreezeフェーズと競合する。

kernel: Freezing remaining freezable tasks aborted after 0.000 seconds
        (1 tasks refusing to freeze, wq_busy=0):
systemd-sleep: Failed to put system to sleep. System resumed again:
        Device or resource busy

カーネルスレッドの1つがfreezeを即座に拒否し、hibernateが失敗する。蓋が閉じたままなのでPowerDevilが再試行し、失敗のループに陥る。

手動のsystemctl hibernateが成功するのは、wakeupsourcehelperが起動されないためである。

wakeupsourcehelperは既にupstreamで無効化されている

PowerDevil 6.5.0以降、upstreamではセキュリティレビュー待ちとしてwakeupsourcehelperが無効化されている。しかしArch Linuxのパッケージ(確認時点で6.6.0)ではまだ有効なまま出荷されている。

logindに処理を委譲するアプローチが使えない理由

「PowerDevilのLidAction=0(何もしない)に設定し、systemd-logindのHandleLidSwitchで処理させる」という方法を試みたが、これは機能しない。

PowerDevilが登録するinhibitorはhandle-lid-switchというlow-levelタイプであり、logind.confのLidSwitchIgnoreInhibited=yesはhigh-levelのinhibitorしか無視しない。

logind.conf(5)より:

Low level inhibitor locks ("handle-power-key", "handle-suspend-key", "handle-hibernate-key", "handle-lid-switch"), are always honored, irrespective of this setting.

さらにこのinhibitor文字列はPowerDevilのソースコードにハードコードされており、設定で無効化することはできない。Bug 385331でも設定可能にする要望がWONTFIXで閉じられている。

対処法

1. wakeupsourcehelperを無効化する

ヘルパーバイナリをリネームして無効化する。

sudo mv /usr/lib/kf6/kauth/wakeupsourcehelper /usr/lib/kf6/kauth/wakeupsourcehelper.disabled

upstreamで既に無効化されている機能なので、実害はない。

2. powerdevilrcでリッドアクションを設定する

~/.config/powerdevilrc:

[AC][SuspendAndShutdown]
LidAction=1
SleepMode=3

[Battery][SuspendAndShutdown]
LidAction=2
SleepMode=3

PowerDevilのSleepModeLidActionの値は以下の通り。

LidAction:

動作
0 何もしない
1 Sleep(SleepModeに従う)
2 Hibernate

SleepMode(LidAction=1のときに使用される):

動作 logind D-Busメソッド
1 Suspend Suspend()
2 Hybrid Sleep HybridSleep()
3 Suspend then Hibernate SuspendThenHibernate()

つまり上記の設定では:

  • バッテリー時: LidAction=2 → PowerDevilがlogindのHibernate()を直接呼ぶ → 即hibernate
  • AC時: LidAction=1 + SleepMode=3 → PowerDevilがlogindのSuspendThenHibernate()を呼ぶ → まずsuspendし、一定時間後にsystemdがhibernateを実行

AC時のhibernateはsystemd自身が実行するため、PowerDevilのwakeupsourcehelperは介在しない。

設定の反映:

qdbus6 org.kde.org_kde_powerdevil /org/kde/Solid/PowerManagement reparseConfiguration

3. suspend-then-hibernateの遅延時間を設定する

/etc/systemd/sleep.conf.d/hibernate-delay.conf:

[Sleep]
HibernateDelaySec=20min

AC時にsuspendしてから20分後にhibernateへ移行する。suspend中にACを抜いてもタイマーは進行するので、「AC接続で蓋を閉じる→ACを抜く→しばらくしてhibernate」という動作になる。

参考


©2024 endaaman.com