Workaround for Linux Mint (Cinnamon) 18.2 Power management

For a variety of reasons, which, indubitably, I will describe in one of my future plaintive posts, I decided (Again!) to switch to a Linux.
Personally, I like Linux Mint Cinnamon, although it has some annoying “features”.
I liked the way it looks very much and now, when they have started to use Unity Greeter – one can admire the beauty of this DE for hours…
But you know, you’d better don’t touch anything, because even if it works – it can easily be broken 😀

Unfortunately, I have been using only laptops for last 7 years and it is imperative that the distro must has a proper power management.
As I understand, Gnome distros can’t brag such ability. Xfce and KDE – can, at least they have all necessary GUI controls.

When I say “power management” I mean a GUI tool that can set
1) display dimming value and timeout
2) display switch off timeout
3) suspend timeout
4) hibernate timeout

These settings must be separate for AC and Battery modes.
Also there shouldn’t be any idiotic behavior or bugs which is common for Linux on desktop.

Linux Mint Cinnamon ALMOST meets all these requirements, but not precisely.

Before release 17.2 there was horrible algorithm of switching off display and hibernation. That algorithm relied on the screen saver.
I do not remember exactly (though I think this algorithm still present in MATE flavor), but it seems that screen saver was in charge of switching off display and putting PC to suspend, i.e. suspend timer worked only when screensaver is active.
All these controls were a part of screen saver. It was inconvenient, but at least it was fair and predictable.

In the release 17.2 things have changed. Since that time screen saver became a separate thing and could be switched off.
Dimming, switching off display and suspend became separate settings, at least visually unrelated to screen saver.
At first glance it seems that you can turn off screen saver, set up appropriate time for screen off and suspend and it will work.
BUT
When screen saver is switched off, system does not recognize changes in power source.

Example:
You have a power plan:
ON AC: never switch off the screen, never suspend
ON BATT: switch off the screen after 5 min, suspend after 10 minutes.

Now, how it works:
System remembers a power state (AC/BATT) which was existing during the boot up or in the moment of closing power settings window by user.
So, If your system had booted on AC and then you unplugged the power cord – system would never notice it and would never go to sleep.

You have two options to prevent this.
1) you can enable screen saver, but its timer must be fired before timers of “display off” and “hibernate”. It seems that the system is checking power state in the moment of starting screen saver, because if you would change the power source again, after screen saver is already started – system remain unaware. I would never find out this myself but thanks to this post.
2) you can manually open power settings dialog and close it. This operation allows system to notice changes in the power source.

The first method is bad and incomplete.
First, I don’t need a screen saver at all and I definitely don’t need it on AC, but you can’t choose to run a screen saver on battery only.
Second – even if you use a screen saver, it can’t help you in case, when the power source is changed after screen saver already has been started.

I noticed this problem two years ago, when Linux Mint 17.2 was released. I wrote a bug report on their forum but no one even commented it. Maybe my English is too bad 🙂
At that time I didn’t noticed that screen saver retained its meaning despite the fact that its settings has a separate place in the interface, so I considered the power management as completely broken and switched to Ubuntu Desktop.

Now, two years later, I decided to give Linux a try once more…
I’ve installed Linux Mint Cinnamon 18.2 and guess what have I found? Absolutely the same crappy power management as it was in the summer of 2015…
But now, I’ve seen Windows 10… Oh, boy… Now I know that there is no “better/easier way”. Only different sorts of crap around and this particular Linux-crap has its indisputable advantages. So I decided to fight a little (poor idiot…).

As I noticed earlier, a simple process of opening and closing of the power management settings in cinnamon forces system to recognize changes in power source. I have spent a lot of time trying to find out what exactly power-management-gui does when it is exiting. I examined /usr/share/cinnamon/cinnamon-settings/modules/cs-power.py but couldn’t find any clues. The only thing I noticed, that the module works with dconf.
I decided to try a simple write procedure in dconf section, related to power manager.

gsettings set org.cinnamon.settings-daemon.plugins.power sleep-display-battery 250

To my surprise it worked. This command not only sets timeout for switching off the display, but also forces system to notice that power source has been changed.

Next, this command must be modified to be run as root, i.e. the root will change the power settings of my user.

#correct_power.sh
DISPLAY=:0 XAUTHORITY=/home/myuser/.Xauthority sudo -u "myuser" -i \
gsettings set org.cinnamon.settings-daemon.plugins.power sleep-display-battery 250

I tried this command as root and as my user and it worked well when I typed it in the terminal. Even more, I could run this command over the ssh from another PC and it made proper changes in power management system.

Next, this command must be launched each time when the power source is changed.
We are going to use udev rules.
In /etc/udev/rules.d I created two files
98-50-AC-power.rules
99-50-batt-power.rules
From which I called a shell script containing gsettings commands

# 98-50-AC-power.rules
SUBSYSTEM=="power_supply", ATTR{online}=="1", RUN+="/path/to/myscript/correct_power.sh"
#
# 99-50-batt-power.rules
SUBSYSTEM=="power_supply", ATTR{online}=="0", RUN+="/path/to/myscript/correct_power.sh"
#

Unfortunately, it didn’t work. This script worked well when was launched by hands or via ssh from another PC, but being launched by udev, the script made changes in dconf without forcing the system to recognize the new power source.
So, I think that something was left behind the scenes. It seems that it is not the writing to dconf itself forces the system to re-read power state, but some side effect. And this side effect is absent when udev is invoking these commands.

Even if udev launches a script which in turn establishes ssh connection to localhost (using password or certificates) an then lunches correct_power.sh – system does not recognize changes in power source.
There was also probability, that problem is in DBUS_SESSION_BUS_ADDRESS, when running from another user. I checked that with no avail.

PID=$(pgrep -f 'gnome-session' | head -n1)
export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-)
DISPLAY=:0 XAUTHORITY=/home/myuser/.Xauthority sudo -u "myuser" -i  \
gsettings set org.cinnamon.settings-daemon.plugins.power sleep-display-battery 250

SOLUTION
My next and final step was a creation of a simple systemd service which waits for signals from udev and runs gsettings upon reception.
That was my last possibility to separate udev from the executed script and put AppArmor off the scent or who it is there thwarting me.
Actually, besides operations on dconf I also move mouse pointer, because I still rely on system idle timer and I must re-initialize it when the power source is changed.
Maybe it is not necessary in Cinnamon. Maybe there are two independent timers here – for AC and BATT sources, but on Unity the timer was one and without re-initialization it could suddenly put the system to suspend.

Simple daemon, written in Perl. I am a little busy now, so I didn’t write a config file for it, although I could and it would be cool feature for power management daemon.
Maybe I will do this later (actually, I moved back to Windows instead 🙂 ).

Perl script
#! /usr/bin/perl
 
use strict;
use utf8;
use IO::File;
 
my $PIDFILE     = '/tmp/pwr_daemon.pid';
 
open(STDIN, '</dev/null');
open(STDOUT, '>/dev/null');
open(STDERR, '>&STDOUT');
 
chdir '/path/to/daemon/file';
 
# there must be only one instance of the daemon
my $pidfh = IO::File->new($PIDFILE, O_WRONLY|O_CREAT|O_EXCL, 0644);
if($pidfh){
    print $pidfh $$;
    close $pidfh;
}else{
    open my $pidfile, '<', $PIDFILE or die "unable to open existing pid file for reading";
    my $pid = <$pidfile>;
    if( $pid =~ /^\d+$/){
      if(kill(0, $pid)){# process exists
        print "daemon process already exists", die;
      }else{# process doesn't exists
        create_pid_file();
      }
    }else{# file corrupted
      create_pid_file();
    }
}
 
 
$SIG{HUP}       = \&do_reload;
 
$SIG{USR1} = sub {
    `DISPLAY=:0 XAUTHORITY=/home/myuser/.Xauthority /usr/bin/xdotool mousemove_relative --sync 0 20`;
    `DISPLAY=:0 XAUTHORITY=/home/myuser/.Xauthority sudo -i -u myuser  gsettings set org.cinnamon.settings-daemon.plugins.power sleep-display-battery 1200`;
    `DISPLAY=:0 XAUTHORITY=/home/myuser/.Xauthority /usr/bin/xdotool mousemove_relative --sync 0 -20`;
};
 
 
$SIG{USR2} = sub {
    `DISPLAY=:0 XAUTHORITY=/home/myuser/.Xauthority /usr/bin/xdotool mousemove_relative --sync 0 20`;
    `DISPLAY=:0 XAUTHORITY=/home/myuser/.Xauthority sudo -i -u myuser  gsettings set org.cinnamon.settings-daemon.plugins.power sleep-display-battery 1200`;
    `DISPLAY=:0 XAUTHORITY=/home/myuser/.Xauthority /usr/bin/xdotool mousemove_relative --sync 0 -20`;
};
 
# main cycle
while(1){
    sleep(5);
}
 
 
sub do_reload{
    unlink $PIDFILE;
    exec './pwr_daemon.pl';
}
 
 
sub create_pid_file{
  unlink $PIDFILE or die "unable to unlink old pidfile";
  my $pidfh = IO::File->new($PIDFILE, O_WRONLY|O_CREAT|O_EXCL, 0644);
  die "unable to create pidfile exlusively" unless $pidfh;
  print $pidfh $$;
  close $pidfh;
}

After that you have to create a file /etc/systemd/system/pwr_daemon.service

[Unit]
Description=Mint power management rectifier
After=syslog.target
After=network.target
 
[Service]
Type=simple
PIDFile=/tmp/pwr_daemon.pid
WorkingDirectory=/path/to/daemon/file
User=myuser
Group=myuser
 
OOMScoreAdjust=-100
ExecStart=/path/to/daemon/file/pwr_daemon.pl
ExecStop=/bin/kill -TERM  $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
 
TimeoutSec=15
RestartSec=15
Restart=always
 
 
[Install]
WantedBy=multi-user.target

Then you have to enable this unit as it is supposed to systemd units.

systemctl enable pwr_daemon

look at its status

systemctl status pwr_daemon

And if everything is OK – run this daemon

systemctl start pwr_daemon

And finally, udev rules has been changed to:

# 98-50-AC-power.rules
SUBSYSTEM=="power_supply", ATTR{online}=="1", RUN+="/usr/bin/pkill -SIGUSR1 -F /tmp/pwr_daemon.pid"
# 99-50-batt-power.rules
SUBSYSTEM=="power_supply", ATTR{online}=="0", RUN+="/usr/bin/pkill -SIGUSR2 -F  /tmp/pwr_daemon.pid"

As you can see, daemon does the same things in both situations so actually, one signal is enough, but I’ve left some free space for future.

That’s it.
I didn’t test it much but it seems to be working 🙂

P.S. Interestingly enough that display dimming doesn’t fit into this scheme. Display dimming on Linux Mint Cinnamon always works fine and works only on battery.
It’s obvious that there is a one more separate system which tracks power source changes…

UPDATE
When Linux Mint 18.3 beta emerged I managed to report a bug on their blog and got an (somewhat lazy) answer from Linux Mint team:

From this answer I understood that they are not considering this as a serious problem and won’t rush to fix it for another 3-5 years.
After a couple of weeks I cooled down and wrote a bug report on gitub as they have suggested.
It’s been 20 days ago – no comments, no status changes…
That’s why Linux has its 2% desktop users. This is what it deserved.

UPDATE
Ha-Ha!
Half a year later I again managed to quickly ask a question on LM blog about power management issue after LM19 beta was announced.
Luckily again I was noticed by someone from LM staff and so github issue on cinnamon-settings-daemon was noticed by LM team as well.
I hope it will have been fixed by release date though it will be too late for me.
I bought a new DELL laptop recently which is quite good, inexpensive and has Windows 10 pro preinstalled.
Linux on a desktop has too many problems an inconveniences. I hope that I won’t be so stupid to mess with this OS on my laptop again.

2 Comments

  • HK says:

    Thank you for investigating this; the issue has been bugging me for a while. Unfortunately, I’ll conclude that there is no practical way to make power management work. This kind of manual tweaks with config files and scripts all over the place tends to give headaches in the future: after a system update, I have to remember that I did this and how, or worse: it could break other things subtly and I will have no clue that it is related to a custom service that I implemented two years ago…

    • koshkamau says:

      Luckily, I recently managed to convey the existence of this problem to Linuxmint staff. At least to somebody, who accepts bug reports on beta releases. They said me that I should post an issue for cinnamon-settings-daemon on github.
      I made it a few days ago.
      https://github.com/linuxmint/cinnamon-settings-daemon/issues/209
      No any reaction so far, but now I have more hope that they will fix it 🙂
      You also could go to github and support this issue.