diff options
Diffstat (limited to 'src/VBox/Main/src-server/HostPower.cpp')
-rw-r--r-- | src/VBox/Main/src-server/HostPower.cpp | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/src/VBox/Main/src-server/HostPower.cpp b/src/VBox/Main/src-server/HostPower.cpp new file mode 100644 index 00000000..55b18dd3 --- /dev/null +++ b/src/VBox/Main/src-server/HostPower.cpp @@ -0,0 +1,208 @@ +/* $Id: HostPower.cpp $ */ +/** @file + * VirtualBox interface to host's power notification service + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_MAIN_HOST +#include "HostPower.h" +#include "LoggingNew.h" + +#include <VBox/com/ptr.h> + +#include "VirtualBoxImpl.h" +#include "MachineImpl.h" + +#include <iprt/mem.h> +#include <iprt/cpp/utils.h> + +HostPowerService::HostPowerService(VirtualBox *aVirtualBox) +{ + AssertPtr(aVirtualBox); + mVirtualBox = aVirtualBox; +} + +HostPowerService::~HostPowerService() +{ +} + +void HostPowerService::notify(Reason_T aReason) +{ + SessionMachinesList machines; + VirtualBox::InternalControlList controls; + + HRESULT rc = S_OK; + + switch (aReason) + { + case Reason_HostSuspend: + { + LogFunc(("HOST SUSPEND\n")); + +#ifdef VBOX_WITH_RESOURCE_USAGE_API + /* Suspend performance sampling to avoid unnecessary callbacks due to jumps in time. */ + PerformanceCollector *perfcollector = mVirtualBox->i_performanceCollector(); + + if (perfcollector) + perfcollector->suspendSampling(); +#endif + mVirtualBox->i_getOpenedMachines(machines, &controls); + + /* pause running VMs */ + for (VirtualBox::InternalControlList::const_iterator it = controls.begin(); + it != controls.end(); + ++it) + { + ComPtr<IInternalSessionControl> pControl = *it; + + /* PauseWithReason() will simply return a failure if + * the VM is in an inappropriate state */ + rc = pControl->PauseWithReason(Reason_HostSuspend); + if (FAILED(rc)) + continue; + + /* save the control to un-pause the VM later */ + mSessionControls.push_back(pControl); + } + + LogRel(("Host suspending: Paused %d VMs\n", mSessionControls.size())); + break; + } + + case Reason_HostResume: + { + LogFunc(("HOST RESUME\n")); + + size_t resumed = 0; + + /* go through VMs we paused on Suspend */ + for (size_t i = 0; i < mSessionControls.size(); ++i) + { + /* note that Resume() will simply return a failure if the VM is + * in an inappropriate state (it will also fail if the VM has + * been somehow closed by this time already so that the + * console reference we have is dead) */ + rc = mSessionControls[i]->ResumeWithReason(Reason_HostResume); + if (FAILED(rc)) + continue; + + ++resumed; + } + + LogRel(("Host resumed: Resumed %d VMs\n", resumed)); + +#ifdef VBOX_WITH_RESOURCE_USAGE_API + /* Resume the performance sampling. */ + PerformanceCollector *perfcollector = mVirtualBox->i_performanceCollector(); + + if (perfcollector) + perfcollector->resumeSampling(); +#endif + + mSessionControls.clear(); + break; + } + + case Reason_HostBatteryLow: + { + LogFunc(("BATTERY LOW\n")); + + Bstr value; + rc = mVirtualBox->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(), + value.asOutParam()); + int fGlobal = 0; + if (SUCCEEDED(rc) && !value.isEmpty()) + { + if (value != "0") + fGlobal = 1; + else if (value == "0") + fGlobal = -1; + } + + mVirtualBox->i_getOpenedMachines(machines, &controls); + size_t saved = 0; + + /* save running VMs */ + for (SessionMachinesList::const_iterator it = machines.begin(); + it != machines.end(); + ++it) + { + ComPtr<SessionMachine> pMachine = *it; + rc = pMachine->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(), + value.asOutParam()); + int fPerVM = 0; + if (SUCCEEDED(rc) && !value.isEmpty()) + { + /* per-VM overrides global */ + if (value != "0") + fPerVM = 2; + else if (value == "0") + fPerVM = -2; + } + + /* default is true */ + if (fGlobal + fPerVM >= 0) + { + ComPtr<IProgress> progress; + + /* SessionMachine::i_saveStateWithReason() will return + * a failure if the VM is in an inappropriate state */ + rc = pMachine->i_saveStateWithReason(Reason_HostBatteryLow, progress); + if (FAILED(rc)) + { + LogRel(("SaveState '%s' failed with %Rhrc\n", pMachine->i_getName().c_str(), rc)); + continue; + } + + /* Wait until the operation has been completed. */ + rc = progress->WaitForCompletion(-1); + if (SUCCEEDED(rc)) + { + LONG iRc; + progress->COMGETTER(ResultCode)(&iRc); + rc = (HRESULT)iRc; + } + + AssertMsg(SUCCEEDED(rc), ("SaveState WaitForCompletion failed with %Rhrc (%#08X)\n", rc, rc)); + + if (SUCCEEDED(rc)) + { + LogRel(("SaveState '%s' succeeded\n", pMachine->i_getName().c_str())); + ++saved; + } + } + } + LogRel(("Battery Low: saved %d VMs\n", saved)); + break; + } + + default: + /* nothing */; + } +} +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ |