From 1dcab6586cd1922376031243b354a6a86b7013a5 Mon Sep 17 00:00:00 2001 From: Natalie Clarius Date: Thu, 31 Aug 2023 17:04:52 +0200 Subject: [PATCH] profiledefaults: don't automatically suspend by default if running in a virtual machine To avoid hangs in virtual environments which don't suppport suspension. BUG: 473835 FIXED-IN: 6.0 --- .../profilegenerator/generate_profiles.cpp | 4 +++- daemon/powerdevilcore.cpp | 4 +++- daemon/powerdevilpowermanagement.cpp | 17 +++++++++++++++++ daemon/powerdevilpowermanagement.h | 1 + daemon/powerdevilprofiledefaults.cpp | 14 ++++++++++++-- daemon/powerdevilprofiledefaults.h | 4 ++-- daemon/powerdevilprofilegenerator.cpp | 8 ++++---- daemon/powerdevilprofilegenerator.h | 3 +-- kcmodule/profiles/EditPage.cpp | 2 ++ 9 files changed, 45 insertions(+), 12 deletions(-) diff --git a/autotests/profilegenerator/generate_profiles.cpp b/autotests/profilegenerator/generate_profiles.cpp index ef6a6c309..f06309502 100644 --- a/autotests/profilegenerator/generate_profiles.cpp +++ b/autotests/profilegenerator/generate_profiles.cpp @@ -31,6 +31,7 @@ int main(int argc, char **argv) "powermanagementprofilesrc in your XDG_CONFIG_HOME, but this tool can produce a brand-new one under any name.")); QCommandLineOption optionMobile("mobile", "Generate profiles for a mobile device (i.e. phones, tablets running Plasma Mobile) instead of regular desktop/laptop."); + QCommandLineOption optionVM("vm", "Generate profiles for a virtual machine environment instead of bare metal."); QCommandLineOption optionCannotSuspendToRam("cannot-suspend-to-ram", "Assume that the device does not support suspending to RAM a.k.a. Sleep."); QCommandLineOption optionCannotSuspendToDisk("cannot-suspend-to-disk", "Assume that the device does not support suspending to disk a.k.a. Hibernate."); parser.addOptions({optionMobile, optionCannotSuspendToRam, optionCannotSuspendToDisk}); @@ -42,6 +43,7 @@ int main(int argc, char **argv) } bool isMobile = parser.isSet(optionMobile); + bool isVM = parser.isSet(optionVM); bool canSuspendToRam = !parser.isSet(optionCannotSuspendToRam); bool canSuspendToDisk = !parser.isSet(optionCannotSuspendToDisk); @@ -55,7 +57,7 @@ int main(int argc, char **argv) QFile::remove(temp_globalrc_path); QFile::remove(parser.positionalArguments()[0]); - PowerDevil::ProfileGenerator::generateProfiles(isMobile, canSuspendToRam, canSuspendToDisk); + PowerDevil::ProfileGenerator::generateProfiles(isMobile, isVM, canSuspendToRam, canSuspendToDisk); if (!QFile::rename(temp_profilesrc_path, parser.positionalArguments()[0])) { qDebug() << "Unable to move config file to destination."; diff --git a/daemon/powerdevilcore.cpp b/daemon/powerdevilcore.cpp index fc0087188..1392bb7ea 100644 --- a/daemon/powerdevilcore.cpp +++ b/daemon/powerdevilcore.cpp @@ -13,6 +13,7 @@ #include "powerdevilactionpool.h" #include "powerdevilenums.h" #include "powerdevilpolicyagent.h" +#include "powerdevilpowermanagement.h" #include "powerdevilprofilegenerator.h" #include @@ -108,8 +109,9 @@ void Core::onBackendReady() // These are generated profiles, const bool mobile = Kirigami::TabletModeWatcher::self()->isTabletMode(); + const bool vm = PowerDevil::PowerManagement::instance()->isVirtualMachine(); - ProfileGenerator::generateProfiles(mobile, toRam, toDisk); + ProfileGenerator::generateProfiles(mobile, vm, toRam, toDisk); m_profilesConfig->reparseConfiguration(); } diff --git a/daemon/powerdevilpowermanagement.cpp b/daemon/powerdevilpowermanagement.cpp index 2e3d85ce9..1f42c82ab 100644 --- a/daemon/powerdevilpowermanagement.cpp +++ b/daemon/powerdevilpowermanagement.cpp @@ -5,6 +5,7 @@ */ #include "powerdevilpowermanagement.h" +#include "powerdevil_debug.h" #include #include @@ -196,6 +197,22 @@ void PowerManagement::suspendThenHibernate() QDBusConnection::sessionBus().asyncCall(message); } +bool PowerManagement::isVirtualMachine() +{ + QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"), + QStringLiteral("/org/freedesktop/systemd1"), + QStringLiteral("org.freedesktop.DBus.Properties"), + QStringLiteral("Get")); + message.setArguments({QStringLiteral("org.freedesktop.systemd1.Manager"), QStringLiteral("Virtualization")}); + QDBusReply reply = QDBusConnection::systemBus().call(message); + if (!reply.isValid() || reply.value().variant().isNull() || reply.value().variant().toString().isNull()) { + qCWarning(POWERDEVIL) << "Failed to get property Virtualization from systemd1 DBus service:" << reply.error().message(); + return false; + } + /* on bare-metal hardware this is the empty string, otherwise an identifier such as "kvm", "vmware", etc. */ + return !reply.value().variant().toString().isEmpty(); +} + bool PowerManagement::canSuspend() const { return d->canSuspend; diff --git a/daemon/powerdevilpowermanagement.h b/daemon/powerdevilpowermanagement.h index 6f4abce65..1e2a4dc8d 100644 --- a/daemon/powerdevilpowermanagement.h +++ b/daemon/powerdevilpowermanagement.h @@ -22,6 +22,7 @@ class POWERDEVILCORE_EXPORT PowerManagement : public QObject public: ~PowerManagement() override; + bool isVirtualMachine(); bool canSuspend() const; bool canHibernate() const; bool canHybridSuspend() const; diff --git a/daemon/powerdevilprofiledefaults.cpp b/daemon/powerdevilprofiledefaults.cpp index eb4f79045..e3b5bc8c8 100644 --- a/daemon/powerdevilprofiledefaults.cpp +++ b/daemon/powerdevilprofiledefaults.cpp @@ -75,8 +75,13 @@ bool ProfileDefaults::defaultLockBeforeTurnOffDisplay(bool isMobile) return isMobile; } -bool ProfileDefaults::defaultAutoSuspendWhenIdle(bool canSuspendToRam) +bool ProfileDefaults::defaultAutoSuspendWhenIdle(bool isVM, bool canSuspendToRam) { + // Don't auto suspend by default when running in a virtual machine as it can cause hangs, + // see bug 473835 + if (isVM) { + return false; + } // Even on AC power, suspend after a rather long period of inactivity. Energy is precious! return canSuspendToRam; } @@ -111,8 +116,13 @@ unsigned int ProfileDefaults::defaultPowerDownAction() return qToUnderlying(PowerButtonAction::PromptLogoutDialog); } -unsigned int ProfileDefaults::defaultLidAction(bool canSuspendToRam) +unsigned int ProfileDefaults::defaultLidAction(bool isVM, bool canSuspendToRam) { + // Don't auto suspend by default when running in a virtual machine as it can cause hangs, + // see bug 473835 + if (isVM) { + return qToUnderlying(PowerButtonAction::NoAction); + } return qToUnderlying(canSuspendToRam ? PowerButtonAction::SuspendToRam : PowerButtonAction::TurnOffScreen); } diff --git a/daemon/powerdevilprofiledefaults.h b/daemon/powerdevilprofiledefaults.h index b874ed3b3..e9c8f570a 100644 --- a/daemon/powerdevilprofiledefaults.h +++ b/daemon/powerdevilprofiledefaults.h @@ -27,13 +27,13 @@ public: static int defaultTurnOffDisplayIdleTimeoutSec(const QString &profileGroup, bool isMobile); static bool defaultLockBeforeTurnOffDisplay(bool isMobile); - static bool defaultAutoSuspendWhenIdle(bool canSuspendToRam); + static bool defaultAutoSuspendWhenIdle(bool isVM, bool canSuspendToRam); static int defaultAutoSuspendIdleTimeoutSec(const QString &profileGroup, bool isMobile); static unsigned int defaultAutoSuspendType(); static unsigned int defaultPowerButtonAction(bool isMobile); static unsigned int defaultPowerDownAction(); - static unsigned int defaultLidAction(bool canSuspendToRam); + static unsigned int defaultLidAction(bool isVM, bool canSuspendToRam); }; } diff --git a/daemon/powerdevilprofilegenerator.cpp b/daemon/powerdevilprofilegenerator.cpp index 1c0202c2c..30b0c2185 100644 --- a/daemon/powerdevilprofilegenerator.cpp +++ b/daemon/powerdevilprofilegenerator.cpp @@ -19,7 +19,7 @@ namespace PowerDevil { -void ProfileGenerator::generateProfiles(bool mobile, bool toRam, bool toDisk) +void ProfileGenerator::generateProfiles(bool mobile, bool vm, bool toRam, bool toDisk) { // Change critical action if default (hibernate) is unavailable if (!toDisk) { @@ -44,7 +44,7 @@ void ProfileGenerator::generateProfiles(bool mobile, bool toRam, bool toDisk) } } - auto initProfile = [toRam, mobile](KConfigGroup &profile) { + auto initProfile = [toRam, mobile, vm](KConfigGroup &profile) { if (ProfileDefaults::defaultUseProfileSpecificDisplayBrightness(profile.name())) { KConfigGroup brightnessControl(&profile, "BrightnessControl"); brightnessControl.writeEntry("value", ProfileDefaults::defaultDisplayBrightness(profile.name())); @@ -53,7 +53,7 @@ void ProfileGenerator::generateProfiles(bool mobile, bool toRam, bool toDisk) KConfigGroup handleButtonEvents(&profile, "HandleButtonEvents"); handleButtonEvents.writeEntry("powerButtonAction", ProfileDefaults::defaultPowerButtonAction(mobile)); handleButtonEvents.writeEntry("powerDownAction", ProfileDefaults::defaultPowerDownAction()); - handleButtonEvents.writeEntry("lidAction", ProfileDefaults::defaultLidAction(toRam)); + handleButtonEvents.writeEntry("lidAction", ProfileDefaults::defaultLidAction(vm, toRam)); if (ProfileDefaults::defaultDimDisplayWhenIdle()) { KConfigGroup dimDisplay(&profile, "DimDisplay"); @@ -66,7 +66,7 @@ void ProfileGenerator::generateProfiles(bool mobile, bool toRam, bool toDisk) dpmsControl.writeEntry("lockBeforeTurnOff", ProfileDefaults::defaultLockBeforeTurnOffDisplay(mobile)); } - if (ProfileDefaults::defaultAutoSuspendWhenIdle(toRam)) { + if (ProfileDefaults::defaultAutoSuspendWhenIdle(vm, toRam)) { KConfigGroup suspendSession(&profile, "SuspendSession"); suspendSession.writeEntry("idleTime", ProfileDefaults::defaultAutoSuspendIdleTimeoutSec(profile.name(), mobile) * 1000); // milliseconds suspendSession.writeEntry("suspendType", ProfileDefaults::defaultAutoSuspendType()); diff --git a/daemon/powerdevilprofilegenerator.h b/daemon/powerdevilprofilegenerator.h index bd92f3dc3..b29f5d06d 100644 --- a/daemon/powerdevilprofilegenerator.h +++ b/daemon/powerdevilprofilegenerator.h @@ -13,7 +13,6 @@ namespace PowerDevil namespace ProfileGenerator { -void POWERDEVILCORE_EXPORT generateProfiles(bool isMobile, bool toRam, bool toDisk); - +void POWERDEVILCORE_EXPORT generateProfiles(bool isMobile, bool isVM, bool toRam, bool toDisk); } } diff --git a/kcmodule/profiles/EditPage.cpp b/kcmodule/profiles/EditPage.cpp index 15210f342..0aa3d65ba 100644 --- a/kcmodule/profiles/EditPage.cpp +++ b/kcmodule/profiles/EditPage.cpp @@ -53,6 +53,7 @@ EditPage::EditPage(QObject *parent, const KPluginMetaData &data) auto interface = Kirigami::TabletModeWatcher::self(); PowerDevil::ProfileGenerator::generateProfiles(interface->isTabletMode(), + PowerDevil::PowerManagement::instance()->isVirtualMachine(), PowerDevil::PowerManagement::instance()->canSuspend(), PowerDevil::PowerManagement::instance()->canHibernate()); m_profilesConfig->reparseConfiguration(); @@ -166,6 +167,7 @@ void EditPage::restoreDefaultProfiles() auto interface = Kirigami::TabletModeWatcher::self(); PowerDevil::ProfileGenerator::generateProfiles(interface->isTabletMode(), + PowerDevil::PowerManagement::instance()->isVirtualMachine(), PowerDevil::PowerManagement::instance()->canSuspend(), PowerDevil::PowerManagement::instance()->canHibernate()); -- GitLab