swaywm/swayidle

systemd/logind IdleAction taken despite not being idle

carloabelli opened this issue · 27 comments

I am trying to enable auto suspend through systemd/logind. In /etc/systemd/logind.conf I have the lines:

IdleAction=suspend
IdleActionSec=1min

However this causes my system to suspend every 1 minute regardless of activity or inactivity. My guess was that sway is not correctly reporting its idle state based on systemd/systemd#1295.

Seems like something that should be implemented in swayidle, but since the decision was made not to handle the dbus session stuff inside the compositor I guess calling SetIdleHint won't be possible (because swayidle is not the session manager). No idea about this actually, it'll probably work

Similarly, the Lock signal should be listened to.

cc @snaggen

Not sure how idle is handled in the logind context, but without the swayidle patch sway are not initializing any idle handling for Wayland. Not sure if that would improve things, but otherwise it could be an idea to look into making wlr idle handling sync the logind idle timers also.

I would probably suggest just turning off the systemd timers and using swayidle alone.

@SirCmpwn is there documentation for using swayidle? I can't seem to find any and man swayidle does not seem to work.

swayidle is only available on the 1.0 alpha, the stable releases do not include it.

busctl --system call org.freedesktop.login1 /org/freedesktop/login1/session/$XDG_SESSION_ID org.freedesktop.login1.Session SetIdleHint $value

for the other way around:

busctl --system get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager BlockInhibited | grep -q '[:"]idle[:"]'

I put the former in a systemd-idle script and the latter in idle_blocked. Then I write swayidle timeout 1 'systemd-idle true' resume 'systemd-idle false' timeout x 'if ! idle_blocked; then swaylock; fi'.

swayidle now listens to the Lock/Unlock signals: #24

I just ran into the same problem:
When changing IdleAction from the default ignore to suspend within /etc/systemd/logind.conf then the laptop even though during keybaord-usage and mouse-usage suspends every IdleActionSec.

Is there a reason not to have swayidle (with logind support) support setting the IdleHint for the session?

No

edrex commented

This doesn't seem to work for me.
I have idlehint 120 in my swayidle command, but logind still suspends every IdleActionSec.

Digging in, I don't see an inhibit from swayidle:

❯ gdbus call -y -d org.freedesktop.login1 -o /org/freedesktop/login1 -m org.freedesktop.login1.Manager.ListInhibitors
([('sleep', 'electron', 'Application cleanup before suspend', 'delay', uint32 1000, uint32 13258), ('sleep', 'NetworkManager', 'NetworkManager needs to turn off networks', 'delay', 0, 653), ('sleep', 'UPower', 'Pause device polling', 'delay', 0, 8951)],)

Actually, it's IdleHint that's not getting the right value:

❯ gdbus call -y -d org.freedesktop.login1 -o /org/freedesktop/login1/session/auto -m org.freedesktop.DBus.Properties.Get org.freedesktop.login1.Session IdleHint
(<true>,)

ref: https://www.freedesktop.org/wiki/Software/systemd/logind/

@electrickite is this the right way to configure?

@edrex The idlehint event will cause swayidle to set the logind IdleHint to True after <seconds> of inactivity. When activity resumes, it will set IdleHint to false.

So idlehint 120 will set IdleHint true after the user is idle for 120 seconds. Logind should then execute its IdleAction after an additional IdleActionSec as configured in logind.conf.

I noticed that IdleHint was only correctly set if swayidle was executed from the sway config using an exec command: it was not able to connect to the D-Bus session if run from the terminal of a logged in session.

edrex commented

I see debug message SetIdleHint 0 but the value on the bus is still True.

The issue seems to be that the SetIdleHint calls are being ignored:

❯ gdbus call -y -d org.freedesktop.login1 -o /org/freedesktop/login1/session/auto -m org.freedesktop.login1.Session.SetIdleHint false                           
()
                                                                                                                                                                                 
~   
❯ gdbus call -y -d org.freedesktop.login1 -o /org/freedesktop/login1/session/auto -m org.freedesktop.DBus.Properties.Get org.freedesktop.login1.Session IdleHint
(<true>,)

I noticed that IdleHint was only correctly set if swayidle was executed from the sway config using an exec command: it was not able to connect to the D-Bus session if run from the terminal of a logged in session.

This is interesting. Does logind ignore SetIdleHint if not called by the session pid? Anyway, swayidle launched from sway config exec doesn't help for me.

Any process can set an inhibit lock. Should swayidle be using this mechanism instead?

Any process can set an inhibit lock. Should swayidle be using this mechanism instead?

The goal of this feature (or at least the PR) is to correctly set the session IdleHint. I would prefer not to use inhibitor locks - they are semantically distinct from the session idle state.

It seems as though SetIdleHint is not being set at all on your system? i.e. even manually calling it via gdbus does not work?

edrex commented

The goal of this feature (or at least the PR) is to correctly set the session IdleHint. I would prefer not to use inhibitor locks - they are semantically distinct from the session idle state.

Ok, I understand

It seems as though SetIdleHint is not being set at all on your system? i.e. even manually calling it via gdbus does not work?

Looks to be. I'm on arch. Does the above work for you?

Logind only checks that the calling process is owned by the session owner:

https://github.com/systemd/systemd/blob/a859abf062cef1511e4879c4ee39c6036ebeaec8/src/login/logind-session-dbus.c#L249

Useful reference: https://www.freedesktop.org/wiki/Software/systemd/writing-desktop-environments/

edrex commented

To verify that the call is getting to logind, tried setting idlehint as another user:

fuser❯ gdbus call -y -d org.freedesktop.login1 -o /org/freedesktop/login1/session/_31 -m org.freedesktop.login1.Session.SetIdleHint false
Error: GDBus.Error:org.freedesktop.DBus.Error.AccessDenied: Only owner of session may set idle hint

gdbus monitor -y -d org.freedesktop.login1 -o /org/freedesktop/login1/session/auto doesn't report any property changes, so it's evidently not some other caller immediately setting it back to true.

Two other reports of similar behavior (calling IdleHint false doesn't change the property value from true):

gdbus monitor -y -d org.freedesktop.login1 -o /org/freedesktop/login1/session/auto doesn't report any property changes, so it's evidently not some other caller immediately setting it back to true.

I don't believe the auto session emits events for idle hint changes. At least from my experiments, I didn't see property change evnts when monitoring the auto session object, but I did if I monitored the actual session object with the session name. (Also on arch)

I noticed that IdleHint was only correctly set if swayidle was executed from the sway config using an exec command: it was not able to connect to the D-Bus session if run from the terminal of a logged in session.

Why would that be? Afaik, logind wouldn't be able to tell if it was started from an exec in config or not.

@edrex FWIW, I just verified that I am able to set the IdleHint for the session from the terminal. (Arch, sway, no display manager). Note that these commands use the session path, as @tmccombs suggests.

$ dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager.ListSessions
method return time=1574128317.662196 sender=:1.8 -> destination=:1.104 serial=70 reply_serial=2
   array [
      struct {
         string "1"
         uint32 1100
         string "corey"
         string "seat0"
         object path "/org/freedesktop/login1/session/_31"
      }
   ]
$ gdbus call -y -d org.freedesktop.login1 -o /org/freedesktop/login1/session/_31 -m org.freedesktop.DBus.Properties.Get org.freedesktop.login1.Session IdleHint
(<false>,)
$ gdbus call -y -d org.freedesktop.login1 -o /org/freedesktop/login1/session/_31 -m org.freedesktop.login1.Session.SetIdleHint true
()
$ gdbus call -y -d org.freedesktop.login1 -o /org/freedesktop/login1/session/_31 -m org.freedesktop.DBus.Properties.Get org.freedesktop.login1.Session IdleHint
(<true>,)

@tmccombs I did a little digging into why swayidle could only set the IdleHint when run from exec in sway config. Turns out it was a different issue: I was running swayidle from bash under the GNOME Terminal emulator. gnome-terminal-server is started as a systemd user service, which are not associated with a particular session. So any child process also lacks a session, meaning that swayidle cannot determine the correct session from its PID.

When run from swaymsg, swayidle is executed within the session context.

edrex commented

I don't believe the auto session emits events for idle hint changes.

Same using explicit session (_31 for me)

I just verified that I am able to set the IdleHint for the session from the terminal.

@electrickite what about setting back to false? The behavior I'm seeing is the props (IdleHint and LockedHint) are stuck true.

Anyway it doesn't look to be specific to swayidle so I sent it upstream. Thanks for engaging with me to troubleshoot.

edrex commented

systemd/systemd#14053 (comment):

currently you can mark a tty session idle, but never unmark it

This feature will not work properly under a TTY session. Perhaps the time has come for a wlroots display manager swaywm/wlroots#540 (comment)

Isn't this a systemd bug?

this is currently be discussed on the systemd side too, see systemd/systemd#14489

Isn't this a systemd bug?

Kind of. My understanding is it is expected (but not ideal) behaviour, because Logind doesn't expect a console session to change into a graphical session.

A PR was merged into systemd today that should land in v246. It adds a SetType method to the logind dbus interface. This will at least allow systemd to support a session type upgrade, although the compositor will still need to implement the switch.

Thanks for your work in pushing that through, @electrickite!