~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Main/darwin/HostPowerDarwin.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/** @file
2
 
 *
3
 
 * VirtualBox interface to host's power notification service
4
 
 */
5
 
 
6
 
/*
7
 
 * Copyright (C) 2008 Oracle Corporation
8
 
 *
9
 
 * This file is part of VirtualBox Open Source Edition (OSE), as
10
 
 * available from http://www.virtualbox.org. This file is free software;
11
 
 * you can redistribute it and/or modify it under the terms of the GNU
12
 
 * General Public License (GPL) as published by the Free Software
13
 
 * Foundation, in version 2 as it comes in the "COPYING" file of the
14
 
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15
 
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16
 
 */
17
 
 
18
 
#include "HostPower.h"
19
 
#include "Logging.h"
20
 
 
21
 
#include <IOKit/IOMessage.h>
22
 
#include <IOKit/ps/IOPowerSources.h>
23
 
#include <IOKit/ps/IOPSKeys.h>
24
 
 
25
 
#define POWER_SOURCE_OUTLET 1
26
 
#define POWER_SOURCE_BATTERY 2
27
 
 
28
 
HostPowerServiceDarwin::HostPowerServiceDarwin (VirtualBox *aVirtualBox)
29
 
  : HostPowerService (aVirtualBox)
30
 
  , mThread (NULL)
31
 
  , mRootPort (MACH_PORT_NULL)
32
 
  , mNotifyPort (nil)
33
 
  , mRunLoop (nil)
34
 
  , mCritical (false)
35
 
{
36
 
    /* Create the new worker thread. */
37
 
    int rc = RTThreadCreate (&mThread, HostPowerServiceDarwin::powerChangeNotificationThread, this, 65536,
38
 
                             RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "MainPower");
39
 
 
40
 
    if (RT_FAILURE(rc))
41
 
        LogFlow (("RTThreadCreate failed with %Rrc\n", rc));
42
 
}
43
 
 
44
 
HostPowerServiceDarwin::~HostPowerServiceDarwin()
45
 
{
46
 
    /* Jump out of the run loop. */
47
 
    CFRunLoopStop (mRunLoop);
48
 
    /* Remove the sleep notification port from the application runloop. */
49
 
    CFRunLoopRemoveSource (CFRunLoopGetCurrent(),
50
 
                           IONotificationPortGetRunLoopSource (mNotifyPort),
51
 
                           kCFRunLoopCommonModes);
52
 
    /* Deregister for system sleep notifications. */
53
 
    IODeregisterForSystemPower (&mNotifierObject);
54
 
    /* IORegisterForSystemPower implicitly opens the Root Power Domain
55
 
     * IOService so we close it here. */
56
 
    IOServiceClose (mRootPort);
57
 
    /* Destroy the notification port allocated by IORegisterForSystemPower */
58
 
    IONotificationPortDestroy (mNotifyPort);
59
 
}
60
 
 
61
 
 
62
 
DECLCALLBACK(int) HostPowerServiceDarwin::powerChangeNotificationThread (RTTHREAD /* ThreadSelf */, void *pInstance)
63
 
{
64
 
    HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *> (pInstance);
65
 
 
66
 
    /* We have to initial set the critical state of the battery, cause we want
67
 
     * not the HostPowerService to inform about that state when a VM starts.
68
 
     * See lowPowerHandler for more info. */
69
 
    pPowerObj->checkBatteryCriticalLevel();
70
 
 
71
 
    /* Register to receive system sleep notifications */
72
 
    pPowerObj->mRootPort = IORegisterForSystemPower (pPowerObj, &pPowerObj->mNotifyPort,
73
 
                                                     HostPowerServiceDarwin::powerChangeNotificationHandler,
74
 
                                                     &pPowerObj->mNotifierObject);
75
 
    if (pPowerObj->mRootPort == MACH_PORT_NULL)
76
 
    {
77
 
        LogFlow (("IORegisterForSystemPower failed\n"));
78
 
        return VERR_NOT_SUPPORTED;
79
 
    }
80
 
    pPowerObj->mRunLoop = CFRunLoopGetCurrent();
81
 
    /* Add the notification port to the application runloop */
82
 
    CFRunLoopAddSource (pPowerObj->mRunLoop,
83
 
                        IONotificationPortGetRunLoopSource (pPowerObj->mNotifyPort),
84
 
                        kCFRunLoopCommonModes);
85
 
 
86
 
    /* Register for all battery change events. The handler will check for low
87
 
     * power events themself. */
88
 
    CFRunLoopSourceRef runLoopSource = IOPSNotificationCreateRunLoopSource(HostPowerServiceDarwin::lowPowerHandler,
89
 
                                                                           pPowerObj);
90
 
    CFRunLoopAddSource(pPowerObj->mRunLoop,
91
 
                       runLoopSource,
92
 
                       kCFRunLoopCommonModes);
93
 
 
94
 
    /* Start the run loop. This blocks. */
95
 
    CFRunLoopRun();
96
 
    return VINF_SUCCESS;
97
 
}
98
 
 
99
 
void HostPowerServiceDarwin::powerChangeNotificationHandler (void *pvData, io_service_t /* service */, natural_t messageType, void *pMessageArgument)
100
 
{
101
 
    HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *> (pvData);
102
 
    Log (( "powerChangeNotificationHandler: messageType %08lx, arg %08lx\n", (long unsigned int)messageType, (long unsigned int)pMessageArgument));
103
 
 
104
 
    switch (messageType)
105
 
    {
106
 
        case kIOMessageCanSystemSleep:
107
 
            {
108
 
                /* Idle sleep is about to kick in. This message will not be
109
 
                 * sent for forced sleep. Applications have a chance to prevent
110
 
                 * sleep by calling IOCancelPowerChange. Most applications
111
 
                 * should not prevent idle sleep. Power Management waits up to
112
 
                 * 30 seconds for you to either allow or deny idle sleep. If
113
 
                 * you don't acknowledge this power change by calling either
114
 
                 * IOAllowPowerChange or IOCancelPowerChange, the system will
115
 
                 * wait 30 seconds then go to sleep. */
116
 
                IOAllowPowerChange (pPowerObj->mRootPort, reinterpret_cast<long> (pMessageArgument));
117
 
                break;
118
 
            }
119
 
        case kIOMessageSystemWillSleep:
120
 
            {
121
 
                /* The system will go for sleep. */
122
 
                pPowerObj->notify (HostPowerEvent_Suspend);
123
 
                /* If you do not call IOAllowPowerChange or IOCancelPowerChange to
124
 
                 * acknowledge this message, sleep will be delayed by 30 seconds.
125
 
                 * NOTE: If you call IOCancelPowerChange to deny sleep it returns
126
 
                 * kIOReturnSuccess, however the system WILL still go to sleep. */
127
 
                IOAllowPowerChange (pPowerObj->mRootPort, reinterpret_cast<long> (pMessageArgument));
128
 
                break;
129
 
            }
130
 
        case kIOMessageSystemWillPowerOn:
131
 
            {
132
 
                /* System has started the wake up process. */
133
 
                break;
134
 
            }
135
 
        case kIOMessageSystemHasPoweredOn:
136
 
            {
137
 
                /* System has finished the wake up process. */
138
 
                pPowerObj->notify (HostPowerEvent_Resume);
139
 
                break;
140
 
            }
141
 
        default:
142
 
            break;
143
 
    }
144
 
}
145
 
 
146
 
void HostPowerServiceDarwin::lowPowerHandler (void *pvData)
147
 
{
148
 
    HostPowerServiceDarwin *pPowerObj = static_cast<HostPowerServiceDarwin *> (pvData);
149
 
 
150
 
    /* Following role for sending the BatteryLow event (5% is critical):
151
 
     * - Not at VM start even if the battery is in an critical state already.
152
 
     * - When the power cord is removed so the power supply change from AC to
153
 
     *   battery & the battery is in an critical state nothing is triggered.
154
 
     *   This has to be discussed.
155
 
     * - When the power supply is the battery & the state of the battery level
156
 
     *   changed from normal to critical. The state transition from critical to
157
 
     *   normal triggers nothing. */
158
 
    bool fCriticalStateChanged = false;
159
 
    pPowerObj->checkBatteryCriticalLevel (&fCriticalStateChanged);
160
 
    if (fCriticalStateChanged)
161
 
        pPowerObj->notify (HostPowerEvent_BatteryLow);
162
 
}
163
 
 
164
 
void HostPowerServiceDarwin::checkBatteryCriticalLevel (bool *pfCriticalChanged)
165
 
{
166
 
    CFTypeRef pBlob = IOPSCopyPowerSourcesInfo();
167
 
    CFArrayRef pSources = IOPSCopyPowerSourcesList (pBlob);
168
 
 
169
 
    CFDictionaryRef pSource = NULL;
170
 
    const void *psValue;
171
 
    bool result;
172
 
    int powerSource = POWER_SOURCE_OUTLET;
173
 
    bool critical = false;
174
 
 
175
 
    if (CFArrayGetCount (pSources) > 0)
176
 
    {
177
 
        for (int i = 0; i < CFArrayGetCount (pSources); ++i)
178
 
        {
179
 
            pSource = IOPSGetPowerSourceDescription (pBlob, CFArrayGetValueAtIndex (pSources, i));
180
 
            /* If the source is empty skip over to the next one. */
181
 
            if (!pSource)
182
 
                continue;
183
 
            /* Skip all power sources which are currently not present like a
184
 
             * second battery. */
185
 
            if (CFDictionaryGetValue (pSource, CFSTR (kIOPSIsPresentKey)) == kCFBooleanFalse)
186
 
                continue;
187
 
            /* Only internal power types are of interest. */
188
 
            result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSTransportTypeKey), &psValue);
189
 
            if (result &&
190
 
                CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSInternalType), 0) == kCFCompareEqualTo)
191
 
            {
192
 
                /* First check which power source we are connect on. */
193
 
                result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSPowerSourceStateKey), &psValue);
194
 
                if (result &&
195
 
                    CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSACPowerValue), 0) == kCFCompareEqualTo)
196
 
                    powerSource = POWER_SOURCE_OUTLET;
197
 
                else if (result &&
198
 
                         CFStringCompare ((CFStringRef)psValue, CFSTR (kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
199
 
                    powerSource = POWER_SOURCE_BATTERY;
200
 
 
201
 
                int curCapacity = 0;
202
 
                int maxCapacity = 1;
203
 
                float remCapacity = 0.0f;
204
 
 
205
 
                /* Fetch the current capacity value of the power source */
206
 
                result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSCurrentCapacityKey), &psValue);
207
 
                if (result)
208
 
                    CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
209
 
                /* Fetch the maximum capacity value of the power source */
210
 
                result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSMaxCapacityKey), &psValue);
211
 
                if (result)
212
 
                    CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
213
 
 
214
 
                /* Calculate the remaining capacity in percent */
215
 
                remCapacity = ((float)curCapacity/(float)maxCapacity * 100.0);
216
 
 
217
 
                /* Check for critical. 5 percent is default. */
218
 
                int criticalValue = 5;
219
 
                result = CFDictionaryGetValueIfPresent (pSource, CFSTR (kIOPSDeadWarnLevelKey), &psValue);
220
 
                if (result)
221
 
                    CFNumberGetValue ((CFNumberRef)psValue, kCFNumberSInt32Type, &criticalValue);
222
 
                critical = (remCapacity < criticalValue);
223
 
                /* We have to take action only if we are on battery, the
224
 
                 * previous state wasn't critical, the state has changed & the
225
 
                 * user requested that info. */
226
 
                if (powerSource == POWER_SOURCE_BATTERY &&
227
 
                    mCritical == false &&
228
 
                    mCritical != critical &&
229
 
                    pfCriticalChanged)
230
 
                    *pfCriticalChanged = true;
231
 
                Log (("checkBatteryCriticalLevel: Remains: %d.%d%% Critical: %d Critical State Changed: %d\n", (int)remCapacity, (int)(remCapacity * 10) % 10, critical, pfCriticalChanged?*pfCriticalChanged:-1));
232
 
            }
233
 
        }
234
 
    }
235
 
    /* Save the new state */
236
 
    mCritical = critical;
237
 
 
238
 
    CFRelease (pBlob);
239
 
    CFRelease (pSources);
240
 
}
241