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 if (SECURITY_DEBUG_LOG_ENABLED()) {
73 secdebug("powerwatch", "powerstates");
74 if (capabilities
& kIOPMSystemPowerStateCapabilityDisk
)
75 secdebug("powerwatch", "disk");
76 if (capabilities
& kIOPMSystemPowerStateCapabilityNetwork
)
77 secdebug("powerwatch", "net");
78 if (capabilities
& kIOPMSystemPowerStateCapabilityAudio
)
79 secdebug("powerwatch", "audio");
80 if (capabilities
& kIOPMSystemPowerStateCapabilityVideo
)
81 secdebug("powerwatch", "video");
84 /* if cpu and no display -> in DarkWake */
85 if ((capabilities
& (kIOPMSystemPowerStateCapabilityCPU
|kIOPMSystemPowerStateCapabilityVideo
)) == kIOPMSystemPowerStateCapabilityCPU
) {
86 secdebug("powerwatch", "enter DarkWake");
87 me
->mInDarkWake
= true;
88 } else if (me
->mInDarkWake
) {
89 secdebug("powerwatch", "exit DarkWake");
90 me
->mInDarkWake
= false;
93 (void)IOPMConnectionAcknowledgeEvent(connection
, token
);
100 IOPowerWatcher::setupDarkWake()
106 ret
= ::IOPMConnectionCreate(CFSTR("IOPowerWatcher"),
107 kIOPMSystemPowerStateCapabilityDisk
108 | kIOPMSystemPowerStateCapabilityNetwork
109 | kIOPMSystemPowerStateCapabilityAudio
110 | kIOPMSystemPowerStateCapabilityVideo
,
112 if (ret
== kIOReturnSuccess
) {
113 ret
= ::IOPMConnectionSetNotification(mIOPMconn
, this,
114 (IOPMEventHandlerType
)iopmcallback
);
115 if (ret
== kIOReturnSuccess
) {
116 ::IOPMConnectionSetDispatchQueue(mIOPMconn
, mIOPMqueue
);
120 dispatch_group_leave(mDarkWakeGroup
);
123 IOPowerWatcher::IOPowerWatcher()
125 if (!(mKernelPort
= ::IORegisterForSystemPower(this, &mPortRef
, ioCallback
, &mHandle
)))
126 UnixError::throwMe(EINVAL
); // no clue
128 mIOPMqueue
= dispatch_queue_create("com.apple.security.IOPowerWatcher", NULL
);
129 if (mIOPMqueue
== NULL
)
132 // Running in background since this will wait for the power
133 // management in configd and we are not willing to block on
134 // that, power events will come in when they do.
135 mDarkWakeGroup
= dispatch_group_create();
136 dispatch_group_enter(mDarkWakeGroup
);
137 dispatch_async(mIOPMqueue
, ^ { setupDarkWake(); });
140 IOPowerWatcher::~IOPowerWatcher()
142 // Make sure to wait until the asynchronous method
143 // finishes, to avoid <rdar://problem/14355434>
144 if (mDarkWakeGroup
) {
145 ::dispatch_group_wait(mDarkWakeGroup
, DISPATCH_TIME_FOREVER
);
146 ::dispatch_release(mDarkWakeGroup
);
149 ::IODeregisterForSystemPower(&mHandle
);
152 ::IOPMConnectionSetDispatchQueue(mIOPMconn
, NULL
);
153 ::IOPMConnectionRelease(mIOPMconn
);
156 ::dispatch_release(mIOPMqueue
);
161 // The callback dispatcher
163 void IOPowerWatcher::ioCallback(void *refCon
, io_service_t service
,
164 natural_t messageType
, void *argument
)
166 IOPowerWatcher
*me
= (IOPowerWatcher
*)refCon
;
167 enum { allow
, refuse
, ignore
} reaction
;
168 switch (messageType
) {
169 case kIOMessageSystemWillSleep
:
170 secdebug("powerwatch", "system will sleep");
171 me
->systemWillSleep();
174 case kIOMessageSystemHasPoweredOn
:
175 secdebug("powerwatch", "system has powered on");
176 me
->systemIsWaking();
179 case kIOMessageSystemWillPowerOff
:
180 secdebug("powerwatch", "system will power off");
181 me
->systemWillPowerDown();
184 case kIOMessageSystemWillNotPowerOff
:
185 secdebug("powerwatch", "system will not power off");
188 case kIOMessageCanSystemSleep
:
189 secdebug("powerwatch", "can system sleep");
192 case kIOMessageSystemWillNotSleep
:
193 secdebug("powerwatch", "system will not sleep");
196 case kIOMessageCanSystemPowerOff
:
197 secdebug("powerwatch", "can system power off");
200 case kIOMessageSystemWillPowerOn
:
201 secdebug("powerwatch", "system will power on");
202 me
->systemWillPowerOn();
206 secdebug("powerwatch",
207 "type 0x%x message received (ignored)", messageType
);
212 // handle acknowledgments
215 secdebug("powerwatch", "calling IOAllowPowerChange");
216 IOAllowPowerChange(me
->mKernelPort
, long(argument
));
219 secdebug("powerwatch", "calling IOCancelPowerChange");
220 IOCancelPowerChange(me
->mKernelPort
, long(argument
));
223 secdebug("powerwatch", "sending no response");
230 // The MachServer hookup
232 PortPowerWatcher::PortPowerWatcher()
234 port(IONotificationPortGetMachPort(mPortRef
));
237 boolean_t
PortPowerWatcher::handle(mach_msg_header_t
*in
)
239 IODispatchCalloutFromMessage(NULL
, in
, mPortRef
);
244 } // end namespace MachPlusPlus
246 } // end namespace Security