HostPowerDarwin.cpp revision c7814cf6e1240a519cbec0441e033d0e2470ed00
/** @file
*
* VirtualBox interface to host's power notification service
*/
/*
* Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include "HostPower.h"
#include "Logging.h"
#include <IOKit/IOMessage.h>
#define POWER_SOURCE_OUTLET 1
#define POWER_SOURCE_BATTERY 2
, mNotifyPort (nil)
, mCritical (false)
{
/* Create the new worker thread. */
int rc = RTThreadCreate (&mThread, HostPowerServiceDarwin::powerChangeNotificationThread, this, 65536,
if (RT_FAILURE(rc))
}
{
/* Jump out of the run loop. */
/* Remove the sleep notification port from the application runloop. */
/* Deregister for system sleep notifications. */
/* IORegisterForSystemPower implicitly opens the Root Power Domain
* IOService so we close it here. */
/* Destroy the notification port allocated by IORegisterForSystemPower */
}
DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread (RTTHREAD /* ThreadSelf */, void *pInstance)
{
/* We have to initial set the critical state of the battery, cause we want
* not the HostPowerService to inform about that state when a VM starts.
* See lowPowerHandler for more info. */
/* Register to receive system sleep notifications */
{
LogFlow (("IORegisterForSystemPower failed\n"));
return VERR_NOT_SUPPORTED;
}
/* Add the notification port to the application runloop */
/* Register for all battery change events. The handler will check for low
* power events itself. */
CFRunLoopSourceRef runLoopSource = IOPSNotificationCreateRunLoopSource(HostPowerServiceDarwin::lowPowerHandler,
/* Start the run loop. This blocks. */
CFRunLoopRun();
return VINF_SUCCESS;
}
void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_service_t /* service */, natural_t messageType, void *pMessageArgument)
{
Log (( "powerChangeNotificationHandler: messageType %08lx, arg %08lx\n", (long unsigned int)messageType, (long unsigned int)pMessageArgument));
switch (messageType)
{
case kIOMessageCanSystemSleep:
{
/* Idle sleep is about to kick in. This message will not be
* sent for forced sleep. Applications have a chance to prevent
* sleep by calling IOCancelPowerChange. Most applications
* should not prevent idle sleep. Power Management waits up to
* 30 seconds for you to either allow or deny idle sleep. If
* you don't acknowledge this power change by calling either
* IOAllowPowerChange or IOCancelPowerChange, the system will
* wait 30 seconds then go to sleep. */
break;
}
{
/* The system will go for sleep. */
/* If you do not call IOAllowPowerChange or IOCancelPowerChange to
* acknowledge this message, sleep will be delayed by 30 seconds.
* NOTE: If you call IOCancelPowerChange to deny sleep it returns
* kIOReturnSuccess, however the system WILL still go to sleep. */
break;
}
{
/* System has started the wake up process. */
break;
}
{
/* System has finished the wake up process. */
break;
}
default:
break;
}
}
{
/* Following role for sending the BatteryLow event (5% is critical):
* - Not at VM start even if the battery is in an critical state already.
* - When the power cord is removed so the power supply change from AC to
* battery & the battery is in an critical state nothing is triggered.
* This has to be discussed.
* - When the power supply is the battery & the state of the battery level
* changed from normal to critical. The state transition from critical to
* normal triggers nothing. */
bool fCriticalStateChanged = false;
}
{
const void *psValue;
bool result;
int powerSource = POWER_SOURCE_OUTLET;
bool critical = false;
if (CFArrayGetCount (pSources) > 0)
{
for (int i = 0; i < CFArrayGetCount (pSources); ++i)
{
/* If the source is empty skip over to the next one. */
if (!pSource)
continue;
/* Skip all power sources which are currently not present like a
* second battery. */
continue;
/* Only internal power types are of interest. */
if (result &&
{
/* First check which power source we are connect on. */
if (result &&
else if (result &&
int curCapacity = 0;
int maxCapacity = 1;
float remCapacity = 0.0f;
/* Fetch the current capacity value of the power source */
if (result)
/* Fetch the maximum capacity value of the power source */
if (result)
/* Calculate the remaining capacity in percent */
/* Check for critical. 5 percent is default. */
int criticalValue = 5;
if (result)
/* We have to take action only if we are on battery, the
* previous state wasn't critical, the state has changed & the
* user requested that info. */
if (powerSource == POWER_SOURCE_BATTERY &&
mCritical == false &&
*pfCriticalChanged = true;
Log (("checkBatteryCriticalLevel: Remains: %d.%d%% Critical: %d Critical State Changed: %d\n", (int)remCapacity, (int)(remCapacity * 10) % 10, critical, pfCriticalChanged?*pfCriticalChanged:-1));
}
}
}
/* Save the new state */
}