Bug 424288 - Unable to inhibit suspend in terminal
Summary: Unable to inhibit suspend in terminal
Status: RESOLVED NOT A BUG
Alias: None
Product: Powerdevil
Classification: Unmaintained
Component: general (other bugs)
Version First Reported In: 5.19.3
Platform: Other Other
: NOR normal
Target Milestone: ---
Assignee: Plasma Bugs List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-07-16 14:09 UTC by basjetimmer
Modified: 2020-08-14 15:05 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed/Implemented In:
Sentry Crash Report:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description basjetimmer 2020-07-16 14:09:02 UTC
SUMMARY
Since the latest update, inhibition of suspend does not seem to be working by issuing dbus commands from the terminal. I have several scripts that look pretty much like this:

```
COOKIE=$(qdbus org.freedesktop.PowerManagement.Inhibit /org/freedesktop/PowerManagement/Inhibit Inhibit string:"Inhibit" string:"User requested")

#perform some long running task, like encoding a video file

qdbus org.freedesktop.PowerManagement.Inhibit /org/freedesktop/PowerManagement/Inhibit UnInhibit uint:$COOKIE
```

However, this is not working anymore and my computer suspends during the long running task. I also have some compiled programs that use the same idea, only by issuing the dbus command through qt's QtDBus-classes. I suspect qbittorrent uses this same method as it also fails to inhibit suspend while downloads are runing since last week.

I understand it has to do with https://invent.kde.org/plasma/powerdevil/commit/d21102cc6c7a4db204a29f376ce5eb316ef57a6e

Is there currently any way to send inhibition from the terminal as I was used to in my scripts?

STEPS TO REPRODUCE

Issue 'qdbus org.freedesktop.PowerManagement.Inhibit /org/freedesktop/PowerManagement/Inhibit Inhibit string:"Inhibit" string:"User requested"', get no error, get a cookie returned.

OBSERVED RESULT

Computer goes to sleep anyway...

EXPECTED RESULT

Suspend is inhibited until I uninhibit it again.

SOFTWARE/OS VERSIONS
Linux/KDE Plasma: Up-to-date Arch
KDE Plasma Version: 5.19.3
KDE Frameworks Version: 5.72.0
Qt Version: 5.15.0
Comment 1 David Edmundson 2020-07-16 14:30:02 UTC
You want something like:

https://gist.githubusercontent.com/fxthomas/9bdfadd972eaf7100b374042faac28c2/raw/94590f2ff10cfb59492c0995fba9a44ec9179691/gnome-inhibit.py

but with the service names and paths replaced

It's less work than whatever you were doing before.

Maybe I should add a kde-inhibit to kde-cli-tools
We have a similar request for nightmode
Comment 2 basjetimmer 2020-07-16 15:26:15 UTC
(In reply to David Edmundson from comment #1)
> You want something like:
> 
> https://gist.githubusercontent.com/fxthomas/9bdfadd972eaf7100b374042faac28c2/
> raw/94590f2ff10cfb59492c0995fba9a44ec9179691/gnome-inhibit.py
> 
> but with the service names and paths replaced
> 
> It's less work than whatever you were doing before.
> 
> Maybe I should add a kde-inhibit to kde-cli-tools
> We have a similar request for nightmode

Thanks for the reply. I do not think that is less work than what I was doing before. I used to just prepend a single line to any script to make it prevent sleep. Now, I need write my scripts, then write another script that calls 'inhibit.py myscript.sh'. Or, create an alias, but then myscript would not work portably if the alias does not exist in another machines env.
Also, suddenly all my scripts depend on python? That's not good.

I'm not sure I understand the reason for this change of behavior. If some programs exited without releasing their inhibition, surely that is a bug in that program not in powerdevil?

Similarly, this is now marked as not a bug, but isn't the command 'qdbus org.freedesktop.PowerManagement.Inhibit /org/freedesktop/PowerManagement/Inhibit Inhibit string:"Inhibit" string:"User requested"' correct? And isn't it supposed to prevent sleep? I feel like the fix for 423131 is a bug.
Comment 3 Kai Uwe Broulik 2020-07-16 15:28:46 UTC
> If some programs exited without releasing their inhibition, surely that is a bug in that program not in powerdevil?

Programs do crash sometimes, you know. It was actually a bug in PowerDevil not releasing those inhibitions properly when the program quit before the inhibition came into effe
Comment 4 David Edmundson 2020-07-16 15:45:13 UTC
>Now, I need write my scripts, then write another script that calls 'inhibit.py myscript.sh'. 

That's maybe avoidable. Something like:

#!/bin/sh
trap 'kill $(jobs -p)' EXIT
inhibit.py read &
rest of my awesome scripts

#the read just to make it hang around, or we could also just change that script to idle after making the call
I can consider that use-case if there is support for a kde-inhibit binary.
Comment 5 basjetimmer 2020-07-16 15:55:27 UTC
> Programs do crash sometimes, you know. 

Yes I do know, but my point stands, a crash in a program is not a bug in powerdevil. Obviously I do see some benefit in powerdevil dealing with this situation, but it is causing me much more trouble than it's solving. 

> It was actually a bug in PowerDevil
> not releasing those inhibitions properly when the program quit before the
> inhibition came into effe

Right, so it shouldn't inhibit if the inhibition was not yet accepted (the first five seconds after requesting?). I see the same thing in the description at d21102cc6c7a4db204a29f376ce5eb316ef57a6e ('remove from pending'). Now, this has obviously been breaking my workflow a bit, but apparently the behavior before was not correct. But now, even when I write a little program like this:

#include <QDBusConnection>
#include <QDBusMessage>
#include <QThread>
#include <QDebug>

class SuspendInhibitor
{
 private:
  bool d_inhibited;
  uint d_cookie;
 public:
  inline SuspendInhibitor() : d_inhibited(false), d_cookie(-1)
  {}

  void inhibitSuspend()
  {
    if (d_inhibited)
      return;
    QDBusMessage inhibitCall = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.PowerManagement.Inhibit"),
                                                              QStringLiteral("/org/freedesktop/PowerManagement/Inhibit"),
                                                              QStringLiteral("org.freedesktop.PowerManagement.Inhibit"),
                                                              QStringLiteral("Inhibit"));
    inhibitCall.setArguments({"Application", "Playing Music"});
    QDBusMessage reply = QDBusConnection::sessionBus().call(inhibitCall, QDBus::Block, 5000);
    if (reply.type() == QDBusMessage::ReplyMessage)
    {
      d_cookie = reply.arguments()[0];
      d_inhibited = true;
    }
  }

  void uninhibitSuspend()
  {
    if (!d_inhibited)
      return;

    QDBusMessage uninhibitcall = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.PowerManagement.Inhibit"),
                                                                QStringLiteral("/org/freedesktop/PowerManagement/Inhibit"),
                                                                QStringLiteral("org.freedesktop.PowerManagement.Inhibit"),
                                                                QStringLiteral("UnInhibit"));
    uninhibitcall.setArguments({d_cookie});
    QDBusMessage reply = QDBusConnection::sessionBus().call(uninhibitcall, QDBus::Block, 5000);
    if (reply.type() == QDBusMessage::ReplyMessage)
      d_inhibited = false;
  }
};

int main()
{
  SuspendInhibitor spnd;
  spnd.inhibitSuspend();

  // Wait for the inhibition to go into effect!!!
  for (uint i = 0; i < 10; ++i)
  {
    qInfo() << "Sleeping " << i + 1;
    QThread::msleep(1000);
  }

  //spnd.uninhibitSuspend();

  qInfo() << "Exiting";

  return 0;
}

And watch org.freedesktop.PowerManagement.Inhibit.HasInhibit, I see somewhere during the 10 sec sleep that I get 'true' as a reply, but then when the program exits, the inhibition is lifted. At this point the inhibit was not pending, it had gone into effect, but it is still removed automatically.
Comment 6 David Edmundson 2020-07-16 16:10:16 UTC
>At this point the inhibit was not pending, it had gone into effect, but it is still removed automatically.

Yes. That sounds right.


My understanding is:

Inhibition should go away on process exit
That was the state in 2010-2015

In 2015 a delay was introduced to workaround chrome posting tiny inhibitions for sound notifications
eca79138c15575f6f523a8680919b407f84da2e2  

This introduced a bug where if you send a request then exit the inhibition stays.

People then started exploiting that bug understandably thinking it was deliberate behaviour (not helped that the specification docs are seemingly also offline)

That bug introduced in 2015 has since been fixed recently.
Comment 7 basjetimmer 2020-07-16 16:26:02 UTC
(In reply to David Edmundson from comment #6)
> >At this point the inhibit was not pending, it had gone into effect, but it is still removed automatically.
> 
> Yes. That sounds right.
> 
> 
> My understanding is:
> 
> Inhibition should go away on process exit
> That was the state in 2010-2015
> 
> In 2015 a delay was introduced to workaround chrome posting tiny inhibitions
> for sound notifications
> eca79138c15575f6f523a8680919b407f84da2e2  
> 
> This introduced a bug where if you send a request then exit the inhibition
> stays.
> 
> People then started exploiting that bug understandably thinking it was
> deliberate behaviour (not helped that the specification docs are seemingly
> also offline)

OK, well that's me I guess :( haha

> 
> That bug introduced in 2015 has since been fixed recently.

OK, I guess I'll have to figure something out. Thanks for your replies.
Comment 8 David Edmundson 2020-07-16 22:54:15 UTC
FYI: https://invent.kde.org/plasma/kde-cli-tools/-/merge_requests/2
Comment 9 David Edmundson 2020-08-14 15:05:17 UTC
Git commit 1f903bb93ce4fdc0f80268dcc23404ace542f70b by David Edmundson.
Committed on 14/08/2020 at 15:04.
Pushed by davidedmundson into branch 'master'.

Add utility to inhibit various actions

People want to use inhibitions with scripts, which is perfectly
sensible.

Most our inhibitors exit when the calling process quits, which is
something we definitely want, but it fails when we have people making
calls with qdbus/dbus-send and wondering why their inhibitions don't
work.

This tiny script puts surfaces all inhibitors in a way that's relatively
easy to use from shell scripts.
Related: bug 422436

M  +1    -0    CMakeLists.txt
A  +3    -0    kdeinhibit/CMakeLists.txt
A  +95   -0    kdeinhibit/main.cpp     [License: GPL (v2)]

https://invent.kde.org/plasma/kde-cli-tools/commit/1f903bb93ce4fdc0f80268dcc23404ace542f70b