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>
34 namespace MachPlusPlus
{
38 // The obligatory empty virtual destructor
40 PowerWatcher::~PowerWatcher()
45 // The default NULL implementations of the callback virtuals.
46 // We define these (rather than leaving them abstract) since
47 // many users want only one of these events.
49 void PowerWatcher::systemWillSleep()
52 void PowerWatcher::systemIsWaking()
55 void PowerWatcher::systemWillPowerDown()
58 void PowerWatcher::systemWillPowerOn()
66 IOPowerWatcher::iopmcallback(void * param
,
67 IOPMConnection connection
,
68 IOPMConnectionMessageToken token
,
69 IOPMSystemPowerStateCapabilities capabilities
)
71 IOPowerWatcher
*me
= (IOPowerWatcher
*)param
;
73 secnotice("powerwatch", "powerstates");
74 if (capabilities
& kIOPMSystemPowerStateCapabilityDisk
)
75 secnotice("powerwatch", "disk");
76 if (capabilities
& kIOPMSystemPowerStateCapabilityNetwork
)
77 secnotice("powerwatch", "net");
78 if (capabilities
& kIOPMSystemPowerStateCapabilityAudio
)
79 secnotice("powerwatch", "audio");
80 if (capabilities
& kIOPMSystemPowerStateCapabilityVideo
)
81 secnotice("powerwatch", "video");
83 /* if cpu and no display -> in DarkWake */
84 if ((capabilities
& (kIOPMSystemPowerStateCapabilityCPU
|kIOPMSystemPowerStateCapabilityVideo
)) == kIOPMSystemPowerStateCapabilityCPU
) {
85 secnotice("powerwatch", "enter DarkWake");
86 me
->mInDarkWake
= true;
87 } else if (me
->mInDarkWake
) {
88 secnotice("powerwatch", "exit DarkWake");
89 me
->mInDarkWake
= false;
92 (void)IOPMConnectionAcknowledgeEvent(connection
, token
);
99 IOPowerWatcher::setupDarkWake()
105 ret
= ::IOPMConnectionCreate(CFSTR("IOPowerWatcher"),
106 kIOPMSystemPowerStateCapabilityDisk
107 | kIOPMSystemPowerStateCapabilityNetwork
108 | kIOPMSystemPowerStateCapabilityAudio
109 | kIOPMSystemPowerStateCapabilityVideo
,
111 if (ret
== kIOReturnSuccess
) {
112 ret
= ::IOPMConnectionSetNotification(mIOPMconn
, this,
113 (IOPMEventHandlerType
)iopmcallback
);
114 if (ret
== kIOReturnSuccess
) {
115 ::IOPMConnectionSetDispatchQueue(mIOPMconn
, mIOPMqueue
);
119 mUserActiveHandle
= IOPMScheduleUserActiveChangedNotification(mIOPMqueue
, ^(bool active
) {
125 dispatch_group_leave(mDarkWakeGroup
);
128 IOPowerWatcher::IOPowerWatcher() :
129 mKernelPort(0), mIOPMconn(NULL
), mIOPMqueue(NULL
), mDarkWakeGroup(NULL
), mUserActiveHandle(NULL
)
131 if (!(mKernelPort
= ::IORegisterForSystemPower(this, &mPortRef
, ioCallback
, &mHandle
)))
132 UnixError::throwMe(EINVAL
); // no clue
134 mIOPMqueue
= dispatch_queue_create("com.apple.security.IOPowerWatcher", NULL
);
135 if (mIOPMqueue
== NULL
)
138 // Running in background since this will wait for the power
139 // management in configd and we are not willing to block on
140 // that, power events will come in when they do.
141 mDarkWakeGroup
= dispatch_group_create();
142 dispatch_group_enter(mDarkWakeGroup
);
143 dispatch_async(mIOPMqueue
, ^ { setupDarkWake(); });
146 IOPowerWatcher::~IOPowerWatcher()
148 // Make sure to wait until the asynchronous method
149 // finishes, to avoid <rdar://problem/14355434>
150 if (mDarkWakeGroup
) {
151 ::dispatch_group_wait(mDarkWakeGroup
, DISPATCH_TIME_FOREVER
);
152 ::dispatch_release(mDarkWakeGroup
);
155 ::IODeregisterForSystemPower(&mHandle
);
158 ::IOPMConnectionSetDispatchQueue(mIOPMconn
, NULL
);
159 ::IOPMConnectionRelease(mIOPMconn
);
161 if (mUserActiveHandle
)
162 ::IOPMUnregisterNotification(mUserActiveHandle
);
164 ::dispatch_release(mIOPMqueue
);
170 // The callback dispatcher
172 void IOPowerWatcher::ioCallback(void *refCon
, io_service_t service
,
173 natural_t messageType
, void *argument
)
175 IOPowerWatcher
*me
= (IOPowerWatcher
*)refCon
;
176 enum { allow
, refuse
, ignore
} reaction
;
177 switch (messageType
) {
178 case kIOMessageSystemWillSleep
:
179 secnotice("powerwatch", "system will sleep");
180 me
->systemWillSleep();
183 case kIOMessageSystemHasPoweredOn
:
184 secnotice("powerwatch", "system has powered on");
185 me
->systemIsWaking();
188 case kIOMessageSystemWillPowerOff
:
189 secnotice("powerwatch", "system will power off");
190 me
->systemWillPowerDown();
193 case kIOMessageSystemWillNotPowerOff
:
194 secnotice("powerwatch", "system will not power off");
197 case kIOMessageCanSystemSleep
:
198 secnotice("powerwatch", "can system sleep");
201 case kIOMessageSystemWillNotSleep
:
202 secnotice("powerwatch", "system will not sleep");
205 case kIOMessageCanSystemPowerOff
:
206 secnotice("powerwatch", "can system power off");
209 case kIOMessageSystemWillPowerOn
:
210 secnotice("powerwatch", "system will power on");
211 me
->systemWillPowerOn();
215 secnotice("powerwatch",
216 "type 0x%x message received (ignored)", messageType
);
221 // handle acknowledgments
224 secnotice("powerwatch", "calling IOAllowPowerChange");
225 IOAllowPowerChange(me
->mKernelPort
, long(argument
));
228 secnotice("powerwatch", "calling IOCancelPowerChange");
229 IOCancelPowerChange(me
->mKernelPort
, long(argument
));
232 secnotice("powerwatch", "sending no response");
239 // The MachServer hookup
241 PortPowerWatcher::PortPowerWatcher()
243 port(IONotificationPortGetMachPort(mPortRef
));
246 boolean_t
PortPowerWatcher::handle(mach_msg_header_t
*in
)
248 IODispatchCalloutFromMessage(NULL
, in
, mPortRef
);
253 } // end namespace MachPlusPlus
255 } // end namespace Security
257 #endif //TARGET_OS_OSX