2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // powerwatch - hook into system notifications of power events
28 #include "powerwatch.h"
29 #include <IOKit/IOMessage.h>
33 namespace MachPlusPlus
{
37 // The obligatory empty virtual destructor
39 PowerWatcher::~PowerWatcher()
44 // The default NULL implementations of the callback virtuals.
45 // We define these (rather than leaving them abstract) since
46 // many users want only one of these events.
48 void PowerWatcher::systemWillSleep()
51 void PowerWatcher::systemIsWaking()
54 void PowerWatcher::systemWillPowerDown()
57 void PowerWatcher::systemWillPowerOn()
65 IOPowerWatcher::iopmcallback(void * param
,
66 IOPMConnection connection
,
67 IOPMConnectionMessageToken token
,
68 IOPMSystemPowerStateCapabilities capabilities
)
70 IOPowerWatcher
*me
= (IOPowerWatcher
*)param
;
72 secnotice("powerwatch", "powerstates");
73 if (capabilities
& kIOPMSystemPowerStateCapabilityDisk
)
74 secnotice("powerwatch", "disk");
75 if (capabilities
& kIOPMSystemPowerStateCapabilityNetwork
)
76 secnotice("powerwatch", "net");
77 if (capabilities
& kIOPMSystemPowerStateCapabilityAudio
)
78 secnotice("powerwatch", "audio");
79 if (capabilities
& kIOPMSystemPowerStateCapabilityVideo
)
80 secnotice("powerwatch", "video");
82 /* if cpu and no display -> in DarkWake */
83 if ((capabilities
& (kIOPMSystemPowerStateCapabilityCPU
|kIOPMSystemPowerStateCapabilityVideo
)) == kIOPMSystemPowerStateCapabilityCPU
) {
84 secnotice("powerwatch", "enter DarkWake");
85 me
->mInDarkWake
= true;
86 } else if (me
->mInDarkWake
) {
87 secnotice("powerwatch", "exit DarkWake");
88 me
->mInDarkWake
= false;
91 (void)IOPMConnectionAcknowledgeEvent(connection
, token
);
98 IOPowerWatcher::setupDarkWake()
104 ret
= ::IOPMConnectionCreate(CFSTR("IOPowerWatcher"),
105 kIOPMSystemPowerStateCapabilityDisk
106 | kIOPMSystemPowerStateCapabilityNetwork
107 | kIOPMSystemPowerStateCapabilityAudio
108 | kIOPMSystemPowerStateCapabilityVideo
,
110 if (ret
== kIOReturnSuccess
) {
111 ret
= ::IOPMConnectionSetNotification(mIOPMconn
, this,
112 (IOPMEventHandlerType
)iopmcallback
);
113 if (ret
== kIOReturnSuccess
) {
114 ::IOPMConnectionSetDispatchQueue(mIOPMconn
, mIOPMqueue
);
118 mUserActiveHandle
= IOPMScheduleUserActiveChangedNotification(mIOPMqueue
, ^(bool active
) {
124 dispatch_group_leave(mDarkWakeGroup
);
127 IOPowerWatcher::IOPowerWatcher() :
128 mKernelPort(0), mIOPMconn(NULL
), mIOPMqueue(NULL
), mDarkWakeGroup(NULL
), mUserActiveHandle(NULL
)
130 if (!(mKernelPort
= ::IORegisterForSystemPower(this, &mPortRef
, ioCallback
, &mHandle
)))
131 UnixError::throwMe(EINVAL
); // no clue
133 mIOPMqueue
= dispatch_queue_create("com.apple.security.IOPowerWatcher", NULL
);
134 if (mIOPMqueue
== NULL
)
137 // Running in background since this will wait for the power
138 // management in configd and we are not willing to block on
139 // that, power events will come in when they do.
140 mDarkWakeGroup
= dispatch_group_create();
141 dispatch_group_enter(mDarkWakeGroup
);
142 dispatch_async(mIOPMqueue
, ^ { setupDarkWake(); });
145 IOPowerWatcher::~IOPowerWatcher()
147 // Make sure to wait until the asynchronous method
148 // finishes, to avoid <rdar://problem/14355434>
149 if (mDarkWakeGroup
) {
150 ::dispatch_group_wait(mDarkWakeGroup
, DISPATCH_TIME_FOREVER
);
151 ::dispatch_release(mDarkWakeGroup
);
154 ::IODeregisterForSystemPower(&mHandle
);
157 ::IOPMConnectionSetDispatchQueue(mIOPMconn
, NULL
);
158 ::IOPMConnectionRelease(mIOPMconn
);
160 if (mUserActiveHandle
)
161 ::IOPMUnregisterNotification(mUserActiveHandle
);
163 ::dispatch_release(mIOPMqueue
);
169 // The callback dispatcher
171 void IOPowerWatcher::ioCallback(void *refCon
, io_service_t service
,
172 natural_t messageType
, void *argument
)
174 IOPowerWatcher
*me
= (IOPowerWatcher
*)refCon
;
175 enum { allow
, refuse
, ignore
} reaction
;
176 switch (messageType
) {
177 case kIOMessageSystemWillSleep
:
178 secnotice("powerwatch", "system will sleep");
179 me
->systemWillSleep();
182 case kIOMessageSystemHasPoweredOn
:
183 secnotice("powerwatch", "system has powered on");
184 me
->systemIsWaking();
187 case kIOMessageSystemWillPowerOff
:
188 secnotice("powerwatch", "system will power off");
189 me
->systemWillPowerDown();
192 case kIOMessageSystemWillNotPowerOff
:
193 secnotice("powerwatch", "system will not power off");
196 case kIOMessageCanSystemSleep
:
197 secnotice("powerwatch", "can system sleep");
200 case kIOMessageSystemWillNotSleep
:
201 secnotice("powerwatch", "system will not sleep");
204 case kIOMessageCanSystemPowerOff
:
205 secnotice("powerwatch", "can system power off");
208 case kIOMessageSystemWillPowerOn
:
209 secnotice("powerwatch", "system will power on");
210 me
->systemWillPowerOn();
214 secnotice("powerwatch",
215 "type 0x%x message received (ignored)", messageType
);
220 // handle acknowledgments
223 secnotice("powerwatch", "calling IOAllowPowerChange");
224 IOAllowPowerChange(me
->mKernelPort
, long(argument
));
227 secnotice("powerwatch", "calling IOCancelPowerChange");
228 IOCancelPowerChange(me
->mKernelPort
, long(argument
));
231 secnotice("powerwatch", "sending no response");
238 // The MachServer hookup
240 PortPowerWatcher::PortPowerWatcher()
242 port(IONotificationPortGetMachPort(mPortRef
));
245 boolean_t
PortPowerWatcher::handle(mach_msg_header_t
*in
)
247 IODispatchCalloutFromMessage(NULL
, in
, mPortRef
);
252 } // end namespace MachPlusPlus
254 } // end namespace Security