I have been using Pop!_OS 19.04 on my Dell XPS ‘13 recently and one of the missing features I wanted back was “suspend then hibernate”. systemd supports suspend-then-hibernate
but as of now, it only supports native hibernation which is not working on my machine. After a lot of experimentation I have settled on a custom script and configuration to get it working.
If you’re interested in getting it working on your machine, follow these steps to enable it:
-
I assume
uswsusp
hibernation is already installed and configured on the target machine. -
Place the provided script somewhere on your file system (I saved it as
/usr/local/bin/s2smart
):#!/bin/bash echo2 () { printf "$1\n" echo "$1" > /dev/kmsg } if [[ $EUID -ne 0 ]]; then echo "This script must be run as root" exit 1 fi hibernate_delay=`cat /etc/systemd/sleep.conf | grep -oP "HibernateDelaySec=\K(\d+)" 2> /dev/null || echo 3600` battery_capacity=`cat /sys/class/power_supply/BAT0/capacity 2> /dev/null || echo 0` if [ $battery_capacity -le 20 ]; then hibernate_delay=$(($hibernate_delay/2)) elif [ $battery_capacity -le 50 ]; then hibernate_delay=$(($hibernate_delay/4)) fi echo2 "Battery capacity at $battery_capacity%%. Will hibernate after $hibernate_delay seconds." # Record current time. curtime=$(date +%s) lock=/tmp/rtchibernate.lock echo "$curtime" > $lock # Entering sleep. echo2 "Entering suspend at $curtime. Will resume in $hibernate_delay seconds." rtcwake -m no -s $hibernate_delay s2ram # Exited the sleep. curtime=$(date +%s) sustime=`cat $lock` rm $lock echo2 "Exited suspend mode at $curtime." # Did we wake up due to the rtc timer above? if [ $(($curtime - $sustime)) -ge $hibernate_delay ]; then # Sometimes when you have too many cores that are too fast run-parts do mess things up. # lets get some sleep ;) sleep 2 # Hibernate (suspend to disk)... echo2 "Entering hibernation mode at $curtime..." s2disk echo2 "Exited hibernation." else # Cancel the rtc timer and wake up normally. rtcwake -m disable echo2 "Cancelled RTC resume prematurely." fi echo2 "Suspend or hibernate finished. Welcome back."
-
Add the line
HibernateDelaySec=3600
into/etc/systemd/sleep.conf
and adjust it to whatever your desired delay is. -
Create a file
override.conf
in/etc/systemd/system/systemd-suspend-then-hibernate.service.d
(create the directory if needed):[Service] ExecStart= ExecStartPre=-/usr/bin/run-parts -v -a pre /usr/lib/systemd/system-sleep ExecStart=/usr/local/bin/s2smart ExecStartPost=-/usr/bin/run-parts -v --reverse -a post /usr/lib/systemd/system-sleep
-
Finally, you will need to enable
suspend-then-hibernate
on lid close by modifying the/etc/systemd/logind.conf
. Make sure the following lines are present and not commented out:HandleLidSwitch=suspend-then-hibernate HandleLidSwitchExternalPower=suspend-then-hibernate
There, hope this helps someone. I did not document all the other steps I took to enable hibernation since those can be found online with ease.