问题描述
是否有可能让Ubuntu从Suspend进入Hibernate状态,又称”Suspend Sedation”?
例如,我的笔记本电脑设置为在关闭盖子后进入暂停状态。如果那时我不使用它一整天,电池就会变平,因为即使在挂起模式下,硬件仍会消耗少量电量,电池最终会放电。我想要的是能够告诉Ubuntu,即使它被暂停,它仍然需要在几个小时的不活动后进入Hibernate。
Windows可以做到这一点。可以将Ubuntu编程为在计时器上进入待机或休眠,但不能同时进入两者。
更新:
我想我需要更具体一点。我正在寻找的是:当我关闭盖子时,笔记本电脑将进入暂停状态。然后,在pre-determined时间之后(即使电池电量很强)如果我仍然不使用它,它应该进入休眠状态以节省电池电量。
最佳解决思路
在Ubuntu 18.04中它更加轻松。在systemd中可以使用新模式suspend-then-hibernate。要开始使用此功能,您需要使用下一个内容创建一个文件/etc/systemd/sleep.conf:
[Sleep]
HibernateDelaySec=3600
然后你可以通过命令测试它:
sudo systemctl suspend-then-hibernate
(您可以编辑HibernateDelaySec以减少休眠延迟)。如果一切正常,你可以改变Lid Close Action,为此你需要编辑文件/etc/systemd/logind.conf
您需要找到选项HandleLidSwitch =,取消注释并更改为HandleLidSwitch = suspend-then-hibernate。然后,您需要通过下一个命令重新启动logind服务(警告!您将重启用户会话):
sudo systemctl restart systemd-logind.service
就这样!现在你可以使用这个不错的功能。
次佳解决思路
解决方案很简单。首先,在暂停和恢复时,pm-suspend程序在/etc/pm/sleep.d
和/usr/lib/pm-utils/sleep.d
中执行一系列脚本。所以我的解决方案是添加一个执行以下操作的脚本:
-
暂停后,记录当前时间并使用rtcwake注册唤醒事件。
-
恢复后,根据上面记录的时间检查当前时间。如果已经过了足够的时间,那么我们可能会因为rtc计时器事件而醒来。否则,我们会因用户事件(例如打开笔记本电脑屏幕)而提前醒来。
-
如果我们因rtc计时器而醒来,则立即发出”pm-hibernate”命令进入休眠状态。
这是一个执行此操作的脚本。将其命名为0000rtchibernate
并将其放在/etc/pm/sleep.d
目录中(0000很重要,因此脚本在挂起时执行,最后在恢复时执行)。
#!/bin/bash
# Script name: /etc/pm/sleep.d/0000rtchibernate
# Purpose: Auto hibernates after a period of sleep
# Edit the "autohibernate" variable below to set the number of seconds to sleep.
curtime=$(date +%s)
autohibernate=7200
echo "$curtime $1" >>/tmp/autohibernate.log
if [ "$1" = "suspend" ]
then
# Suspending. Record current time, and set a wake up timer.
echo "$curtime" >/var/run/pm-utils/locks/rtchibernate.lock
rtcwake -m no -s $autohibernate
fi
if [ "$1" = "resume" ]
then
# Coming out of sleep
sustime=$(cat /var/run/pm-utils/locks/rtchibernate.lock)
rm /var/run/pm-utils/locks/rtchibernate.lock
# Did we wake up due to the rtc timer above?
if [ $(($curtime - $sustime)) -ge $autohibernate ]
then
# Then hibernate
rm /var/run/pm-utils/locks/pm-suspend.lock
/usr/sbin/pm-hibernate
else
# Otherwise cancel the rtc timer and wake up normally.
rtcwake -m no -s 1
fi
fi
希望这个代码在这个留言板上出现(这是我在这里的第一篇文章)。
编辑顶部的超时值autohibernate=7200
,无论您在进入休眠状态之前要睡多少秒。上面的当前值是2小时。请注意,当笔记本电脑执行休眠功能时,笔记本电脑将在此时唤醒几秒钟。
因此,如果您打算将笔记本电脑放在机箱中,请不要暂停,而是暂停休眠。否则你的笔记本电脑可能会过热。如果是在一个紧身滑动的情况下(虽然它只会持续几秒到一分钟)。
在过去的几天里,我一直在使用这种方法,到目前为止它已经成功(并且今天下午让我免于死电)。请享用。
对于使用systemd
和更新的Ubuntu版本的其他Linux发行版,如果将脚本放在/usr/lib/systemd/system-sleep
而不是/etc/pm/sleep.d
中,这仍然有用。另外,用systemctl hibernate
替换/usr/sbin/pm-hibernate
命令。
第三种解决思路
用简单的话来解释它是如何工作的(这类似于Windows):当电池电量不足以便能够将机器状态保存到交换分区时,机器不会从待机状态唤醒,它会立即将所有内容保存到交换分区在待机状态下,当电池电量耗尽时,它将通过从交换分区加载状态来恢复(就像你休眠时一样)。
AFAIK linux将/应该使用混合备用/休眠而不是”normal”备用,如果它知道它适用于您的硬件。目前也可能因为太多错误或其他原因而被禁用…;)
如果你喜欢试验,也许你可以看看你是否可以用pm-suspend-hybrid获得任何好的结果。
如果以下说你很幸运,那么理论上你的系统支持混合暂停:
pm-is-supported --suspend-hybrid && echo "you're lucky"
第四种思路
可能感兴趣:s2both。它由Ubuntu 10.10中的uswsusp
包提供。它挂起到磁盘,但不是关闭系统而是将其放入S3,这是通常与Ubuntu中的”Suspend”选项相关联的电源模式。 pm-suspend-hybrid是另一种声称可以做同样事情的工具。
要使盖子上的自动关闭,请查看以下指南,该指南允许您在捕获盖子事件时运行任意脚本:
http://ubuntuforums.org/showthread.php?t=1076486
如果碰巧有ThinkPad,tpctl
的联机帮助页引用了一个参数--pm-sedation-hibernate-from-suspend-timer
,它似乎提供了您正在寻找的功能。我会提醒您不要在non-ThinkPad硬件上尝试此操作。
作为参考,我查看了hibernate.conf的联机帮助页;它似乎没有任何相关的选择,但可能值得二读。
第五种思路
Ubuntu 16.04 – 在pre-determined时间之后从暂停/睡眠进入休眠状态
似乎在Ubuntu 16.04上的东西有点不同,所以我采取的步骤是:
-
确保hibernate在运行时按预期工作
systemctl hibernate
-
复制原始
suspend.target
文件:sudo cp /lib/systemd/system/suspend.target /etc/systemd/system/suspend.target
然后编辑文件
/etc/systemd/system/suspend.target
并添加以下行:Requires=delayed-hibernation.service
到该文件的
[Unit]
部分。 -
使用以下内容创建文件
/etc/systemd/system/delayed-hibernation.service
:
[Unit]
Description=Delayed hibernation trigger
Before=suspend.target
Conflicts=hibernate.target hybrid-suspend.target
StopWhenUnneeded=true
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/delayed-hibernation.sh pre suspend
ExecStop=/usr/local/bin/delayed-hibernation.sh post suspend
[Install]
WantedBy=sleep.target
-
使用以下内容为脚本创建配置文件
/etc/delayed-hibernation.conf
:
# Configuration file for 'delayed-hibernation.sh' script
# Specify the time in seconds to spend in sleep mode before the computer hibernates
TIMEOUT=1200 #in seconds, gives 20 minutes
-
创建实际完成艰苦工作的脚本。使用以下内容创建文件
/usr/local/bin/delayed-hibernation.sh
:
#!/bin/bash
# Script name: delayed-hibernation.sh
# Purpose: Auto hibernates after a period of sleep
# Edit the `TIMEOUT` variable in the `$hibernation_conf` file to set the number of seconds to sleep.
hibernation_lock='/var/run/delayed-hibernation.lock'
hibernation_fail='/var/run/delayed-hibernation.fail'
hibernation_conf='/etc/delayed-hibernation.conf'
# Checking the configuration file
if [ ! -f $hibernation_conf ]; then
echo "Missing configuration file ('$hibernation_conf'), aborting."
exit 1
fi
hibernation_timeout=$(grep "^[^#]" $hibernation_conf | grep "TIMEOUT=" | awk -F'=' '{ print $2 }' | awk -F'#' '{print $1}' | tr -d '[[ \t]]')
if [ "$hibernation_timeout" = "" ]; then
echo "Missing 'TIMEOUT' parameter from configuration file ('$hibernation_conf'), aborting."
exit 1
elif [[ ! "$hibernation_timeout" =~ ^[0-9]+$ ]]; then
echo "Bad 'TIMEOUT' parameter ('$hibernation_timeout') in configuration file ('$hibernation_conf'), expected number of seconds, aborting."
exit 1
fi
# Processing given parameters
if [ "$2" = "suspend" ]; then
curtime=$(date +%s)
if [ "$1" = "pre" ]; then
if [ -f $hibernation_fail ]; then
echo "Failed hibernation detected, skipping setting RTC wakeup timer."
else
echo "Suspend detected. Recording time, set RTC timer"
echo "$curtime" > $hibernation_lock
rtcwake -m no -s $hibernation_timeout
fi
elif [ "$1" = "post" ]; then
if [ -f $hibernation_fail ]; then
rm $hibernation_fail
fi
if [ -f $hibernation_lock ]; then
sustime=$(cat $hibernation_lock)
rm $hibernation_lock
if [ $(($curtime - $sustime)) -ge $hibernation_timeout ]; then
echo "Automatic resume from suspend detected. Hibernating..."
systemctl hibernate
if [ $? -ne 0 ]; then
echo "Automatic hibernation failed. Trying to suspend instead."
touch $hibernation_fail
systemctl suspend
if [ $? -ne 0 ]; then
echo "Automatic hibernation and suspend failover failed. Nothing else to try."
fi
fi
else
echo "Manual resume from suspend detected. Clearing RTC timer"
rtcwake -m disable
fi
else
echo "File '$hibernation_lock' was not found, nothing to do"
fi
else
echo "Unrecognised first parameter: '$1', expected 'pre' or 'post'"
fi
else
echo "This script is intended to be run by systemctl delayed-hibernation.service (expected second parameter: 'suspend')"
fi
-
使脚本可执行:
chmod 755 /usr/local/bin/delayed-hibernation.sh
在我根据这个帖子中的其他回复编写这个脚本之前我花了很多东西,我在互联网上找到的东西,比如https://bbs.archlinux.org/viewtopic.php?pid=1554259
我的脚本版本尝试处理许多问题,例如如果hibernate没有成功则再次进入暂停,但在pre-determined时间之后不要再次唤醒。
-
我假设的最后一步是执行
sudo systemctl daemon-reload sudo systemctl enable delayed-hibernation.service
确保使用新的服务/配置。
要检查服务日志,您可以使用:
sudo systemctl status delayed-hibernation.service
或者有关服务使用的完整日志:
sudo journalctl -u delayed-hibernation.service
我从正在运行的服务获得的正常日志是:
mile@mile-ThinkPad:~$ sudo systemctl status delayed-hibernation.service
● delayed-hibernation.service - Delayed hibernation trigger
Loaded: loaded (/etc/systemd/system/delayed-hibernation.service; enabled; vendor preset: enabled)
Active: inactive (dead)
Jun 09 20:35:42 mile-ThinkPad systemd[1]: Starting Delayed hibernation trigger...
Jun 09 20:35:42 mile-ThinkPad delayed-hibernation.sh[2933]: Suspend detected. Recording time, set RTC timer
Jun 09 20:35:42 mile-ThinkPad delayed-hibernation.sh[2933]: rtcwake: assuming RTC uses UTC ...
Jun 09 20:35:42 mile-ThinkPad delayed-hibernation.sh[2933]: rtcwake: wakeup using /dev/rtc0 at Thu Jun 9 18:55:43 2016
Jun 09 20:55:44 mile-ThinkPad systemd[1]: Started Delayed hibernation trigger.
Jun 09 20:55:44 mile-ThinkPad systemd[1]: delayed-hibernation.service: Unit not needed anymore. Stopping.
Jun 09 20:55:44 mile-ThinkPad systemd[1]: Stopping Delayed hibernation trigger...
Jun 09 20:55:44 mile-ThinkPad delayed-hibernation.sh[3093]: Automatic resume from suspend detected. Hibernating...
Jun 09 20:55:44 mile-ThinkPad systemd[1]: Stopped Delayed hibernation trigger.
mile@mile-ThinkPad:~$
所以这就是它,我希望它真的能帮助别人,因为我花了几天时间试图找出配置和脚本版本的正确组合,以使这个方便的功能工作。
第六种思路
为了防止在pm-hibernate期间出现问题,我宁愿让计算机暂停而不是让它运行。所以你可以使用:
...
/usr/sbin/pm-hibernate || /usr/sbin/pm-suspend
...
第七种思路
这是Derek Pressnall’s answer的更新版本,它与systemd一起使用并包含Eliah Kagan’s suggestion,只需将其放入/usr/lib/systemd/system-sleep/delayed_hibernation.sh并使其可执行:
#!/bin/bash
hibernation_timeout=1800 #30 minutes
if [ "$2" = "suspend" ]; then
curtime=$(date +%s)
if [ "$1" = "pre" ]; then
echo -e "[($curtime) $@]\nExecuting pre-suspend hook..." >> /tmp/delayed_hibernation.log
echo "$curtime" > /var/run/delayed_hibernation.lock
rtcwake -m no -s $hibernation_timeout
elif [ "$1" = "post" ]; then
echo -e "[($curtime) $@]\nExecuting post-suspend hook..." >> /tmp/delayed_hibernation.log
sustime=$(cat /var/run/delayed_hibernation.lock)
if [ $(($curtime - $sustime)) -ge $hibernation_timeout ]; then
echo -e "Automatic resume detected, hibernating.\n" >> /tmp/delayed_hibernation.log
systemctl hibernate || systemctl suspend
else
echo -e "Manual resume detected, clearing RTC alarm.\n" >> /tmp/delayed_hibernation.log
rtcwake -m no -s 1
fi
rm /var/run/delayed_hibernation.lock
fi
fi
第八种思路
这是我的食谱(在两个笔记本Ubuntu 16.04上测试过):
把这个脚本放在你喜欢的地方(我把它放到root,/syspend.sh
)并使它可执行(chmod +x /suspend.sh
)
TIMELOG=/tmp/autohibernate.log
ALARM=$(tail -n 1 $TIMELOG)
SLEEPTIME=5000 #edit this line to change timer, e.g. 2 hours "$((2*60*60))"
if [[ $1 == "resume" ]]
then
if [[ $(date +%s) -ge $(( $ALARM + $SLEEPTIME )) ]]
then
echo "hibernate triggered $(date +%H:%M:%S)">>$TIMELOG
systemctl hibernate 2>> $TIMELOG
else
echo "normal wakeup $(date +%H:%M:%S)">>$TIMELOG
fi
elif [[ $1 == "suspend" ]]
then
echo "$(date +%s)" >> $TIMELOG
rtcwake -m no -s $SLEEPTIME
fi
然后创建systemd目标:# touch /etc/systemd/system/suspend-to-sleep.target
粘贴此内容:
#/etc/systemd/system/suspend-to-hibernate.service
[Unit]
Description=Delayed hibernation trigger
Before=suspend.target
Conflicts=hibernate.target hybrid-suspend.target
StopWhenUnneeded=true
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash /suspend.sh suspend
ExecStop=/bin/bash /suspend.sh wakeup
[Install]
WantedBy=sleep.target
RequiredBy=suspend.target
然后启用它# systemctl enable suspend-to-sleep.target
。
我在笔记本电脑上遇到了一个问题:关闭盖子没有触发这个目标。这是由于xfce4-power-manager。有两种方法可以解决此问题。第一个是编辑/etc/systemd/logind.conf
文件并用HandleLidSwitch=suspend
替换HandleLidSwitch=ignore
。但它将是系统范围的,所以我只是将symlink添加到我的脚本# ln -s /suspend.sh /etc/pm/sleep.d/0000rtchibernate