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 mUserActiveHandle
= IOPMScheduleUserActiveChangedNotification(mIOPMqueue
, ^(bool active
) {
126 dispatch_group_leave(mDarkWakeGroup
);
129 IOPowerWatcher::IOPowerWatcher() :
130 mKernelPort(0), mIOPMconn(NULL
), mIOPMqueue(NULL
), mDarkWakeGroup(NULL
), mUserActiveHandle(NULL
)
132 if (!(mKernelPort
= ::IORegisterForSystemPower(this, &mPortRef
, ioCallback
, &mHandle
)))
133 UnixError::throwMe(EINVAL
); // no clue
135 mIOPMqueue
= dispatch_queue_create("com.apple.security.IOPowerWatcher", NULL
);
136 if (mIOPMqueue
== NULL
)
139 // Running in background since this will wait for the power
140 // management in configd and we are not willing to block on
141 // that, power events will come in when they do.
142 mDarkWakeGroup
= dispatch_group_create();
143 dispatch_group_enter(mDarkWakeGroup
);
144 dispatch_async(mIOPMqueue
, ^ { setupDarkWake(); });
147 IOPowerWatcher::~IOPowerWatcher()
149 // Make sure to wait until the asynchronous method
150 // finishes, to avoid <rdar://problem/14355434>
151 if (mDarkWakeGroup
) {
152 ::dispatch_group_wait(mDarkWakeGroup
, DISPATCH_TIME_FOREVER
);
153 ::dispatch_release(mDarkWakeGroup
);
156 ::IODeregisterForSystemPower(&mHandle
);
159 ::IOPMConnectionSetDispatchQueue(mIOPMconn
, NULL
);
160 ::IOPMConnectionRelease(mIOPMconn
);
162 if (mUserActiveHandle
)
163 ::IOPMUnregisterNotification(mUserActiveHandle
);
165 ::dispatch_release(mIOPMqueue
);
171 // The callback dispatcher
173 void IOPowerWatcher::ioCallback(void *refCon
, io_service_t service
,
174 natural_t messageType
, void *argument
)
176 IOPowerWatcher
*me
= (IOPowerWatcher
*)refCon
;
177 enum { allow
, refuse
, ignore
} reaction
;
178 switch (messageType
) {
179 case kIOMessageSystemWillSleep
:
180 secdebug("powerwatch", "system will sleep");
181 me
->systemWillSleep();
184 case kIOMessageSystemHasPoweredOn
:
185 secdebug("powerwatch", "system has powered on");
186 me
->systemIsWaking();
189 case kIOMessageSystemWillPowerOff
:
190 secdebug("powerwatch", "system will power off");
191 me
->systemWillPowerDown();
194 case kIOMessageSystemWillNotPowerOff
:
195 secdebug("powerwatch", "system will not power off");
198 case kIOMessageCanSystemSleep
:
199 secdebug("powerwatch", "can system sleep");
202 case kIOMessageSystemWillNotSleep
:
203 secdebug("powerwatch", "system will not sleep");
206 case kIOMessageCanSystemPowerOff
:
207 secdebug("powerwatch", "can system power off");
210 case kIOMessageSystemWillPowerOn
:
211 secdebug("powerwatch", "system will power on");
212 me
->systemWillPowerOn();
216 secdebug("powerwatch",
217 "type 0x%x message received (ignored)", messageType
);
222 // handle acknowledgments
225 secdebug("powerwatch", "calling IOAllowPowerChange");
226 IOAllowPowerChange(me
->mKernelPort
, long(argument
));
229 secdebug("powerwatch", "calling IOCancelPowerChange");
230 IOCancelPowerChange(me
->mKernelPort
, long(argument
));
233 secdebug("powerwatch", "sending no response");
240 // The MachServer hookup
242 PortPowerWatcher::PortPowerWatcher()
244 port(IONotificationPortGetMachPort(mPortRef
));
247 boolean_t
PortPowerWatcher::handle(mach_msg_header_t
*in
)
249 IODispatchCalloutFromMessage(NULL
, in
, mPortRef
);
254 } // end namespace MachPlusPlus
256 } // end namespace Security