]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
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 | |
11 | * file. | |
12 | * | |
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. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | // | |
26 | // powerwatch - hook into system notifications of power events | |
27 | // | |
28 | #include "powerwatch.h" | |
29 | #include <IOKit/IOMessage.h> | |
30 | ||
866f8763 | 31 | #if TARGET_OS_OSX |
b1ab9ed8 A |
32 | |
33 | namespace Security { | |
34 | namespace MachPlusPlus { | |
35 | ||
36 | ||
37 | // | |
38 | // The obligatory empty virtual destructor | |
39 | // | |
40 | PowerWatcher::~PowerWatcher() | |
41 | { } | |
42 | ||
43 | ||
44 | // | |
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. | |
48 | // | |
49 | void PowerWatcher::systemWillSleep() | |
50 | { } | |
51 | ||
52 | void PowerWatcher::systemIsWaking() | |
53 | { } | |
54 | ||
55 | void PowerWatcher::systemWillPowerDown() | |
56 | { } | |
57 | ||
58 | void PowerWatcher::systemWillPowerOn() | |
59 | { } | |
60 | ||
61 | // | |
62 | // IOPowerWatchers | |
63 | // | |
64 | ||
65 | void | |
66 | IOPowerWatcher::iopmcallback(void * param, | |
67 | IOPMConnection connection, | |
68 | IOPMConnectionMessageToken token, | |
69 | IOPMSystemPowerStateCapabilities capabilities) | |
70 | { | |
71 | IOPowerWatcher *me = (IOPowerWatcher *)param; | |
72 | ||
fa7225c8 | 73 | secnotice("powerwatch", "powerstates"); |
b1ab9ed8 | 74 | if (capabilities & kIOPMSystemPowerStateCapabilityDisk) |
fa7225c8 | 75 | secnotice("powerwatch", "disk"); |
b1ab9ed8 | 76 | if (capabilities & kIOPMSystemPowerStateCapabilityNetwork) |
fa7225c8 | 77 | secnotice("powerwatch", "net"); |
b1ab9ed8 | 78 | if (capabilities & kIOPMSystemPowerStateCapabilityAudio) |
fa7225c8 | 79 | secnotice("powerwatch", "audio"); |
b1ab9ed8 | 80 | if (capabilities & kIOPMSystemPowerStateCapabilityVideo) |
fa7225c8 | 81 | secnotice("powerwatch", "video"); |
b1ab9ed8 A |
82 | |
83 | /* if cpu and no display -> in DarkWake */ | |
84 | if ((capabilities & (kIOPMSystemPowerStateCapabilityCPU|kIOPMSystemPowerStateCapabilityVideo)) == kIOPMSystemPowerStateCapabilityCPU) { | |
fa7225c8 | 85 | secnotice("powerwatch", "enter DarkWake"); |
b1ab9ed8 A |
86 | me->mInDarkWake = true; |
87 | } else if (me->mInDarkWake) { | |
fa7225c8 | 88 | secnotice("powerwatch", "exit DarkWake"); |
b1ab9ed8 A |
89 | me->mInDarkWake = false; |
90 | } | |
91 | ||
92 | (void)IOPMConnectionAcknowledgeEvent(connection, token); | |
93 | ||
94 | return; | |
95 | } | |
96 | ||
97 | ||
98 | void | |
99 | IOPowerWatcher::setupDarkWake() | |
100 | { | |
101 | IOReturn ret; | |
102 | ||
103 | mInDarkWake = false; | |
104 | ||
b1ab9ed8 A |
105 | ret = ::IOPMConnectionCreate(CFSTR("IOPowerWatcher"), |
106 | kIOPMSystemPowerStateCapabilityDisk | |
107 | | kIOPMSystemPowerStateCapabilityNetwork | |
108 | | kIOPMSystemPowerStateCapabilityAudio | |
109 | | kIOPMSystemPowerStateCapabilityVideo, | |
110 | &mIOPMconn); | |
427c49bc A |
111 | if (ret == kIOReturnSuccess) { |
112 | ret = ::IOPMConnectionSetNotification(mIOPMconn, this, | |
113 | (IOPMEventHandlerType)iopmcallback); | |
114 | if (ret == kIOReturnSuccess) { | |
115 | ::IOPMConnectionSetDispatchQueue(mIOPMconn, mIOPMqueue); | |
116 | } | |
117 | } | |
118 | ||
5c19dc3a A |
119 | mUserActiveHandle = IOPMScheduleUserActiveChangedNotification(mIOPMqueue, ^(bool active) { |
120 | if (active) { | |
121 | mInDarkWake = false; | |
122 | } | |
123 | }); | |
124 | ||
427c49bc | 125 | dispatch_group_leave(mDarkWakeGroup); |
b1ab9ed8 A |
126 | } |
127 | ||
5c19dc3a A |
128 | IOPowerWatcher::IOPowerWatcher() : |
129 | mKernelPort(0), mIOPMconn(NULL), mIOPMqueue(NULL), mDarkWakeGroup(NULL), mUserActiveHandle(NULL) | |
b1ab9ed8 | 130 | { |
427c49bc A |
131 | if (!(mKernelPort = ::IORegisterForSystemPower(this, &mPortRef, ioCallback, &mHandle))) |
132 | UnixError::throwMe(EINVAL); // no clue | |
133 | ||
134 | mIOPMqueue = dispatch_queue_create("com.apple.security.IOPowerWatcher", NULL); | |
135 | if (mIOPMqueue == NULL) | |
136 | return; | |
137 | ||
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(); }); | |
b1ab9ed8 A |
144 | } |
145 | ||
146 | IOPowerWatcher::~IOPowerWatcher() | |
147 | { | |
427c49bc A |
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); | |
153 | } | |
b1ab9ed8 A |
154 | if (mKernelPort) |
155 | ::IODeregisterForSystemPower(&mHandle); | |
156 | ||
157 | if (mIOPMconn) { | |
158 | ::IOPMConnectionSetDispatchQueue(mIOPMconn, NULL); | |
159 | ::IOPMConnectionRelease(mIOPMconn); | |
160 | } | |
5c19dc3a A |
161 | if (mUserActiveHandle) |
162 | ::IOPMUnregisterNotification(mUserActiveHandle); | |
b1ab9ed8 A |
163 | if (mIOPMqueue) |
164 | ::dispatch_release(mIOPMqueue); | |
5c19dc3a | 165 | |
b1ab9ed8 A |
166 | } |
167 | ||
168 | ||
169 | // | |
170 | // The callback dispatcher | |
171 | // | |
172 | void IOPowerWatcher::ioCallback(void *refCon, io_service_t service, | |
173 | natural_t messageType, void *argument) | |
174 | { | |
175 | IOPowerWatcher *me = (IOPowerWatcher *)refCon; | |
176 | enum { allow, refuse, ignore } reaction; | |
177 | switch (messageType) { | |
178 | case kIOMessageSystemWillSleep: | |
fa7225c8 | 179 | secnotice("powerwatch", "system will sleep"); |
b1ab9ed8 A |
180 | me->systemWillSleep(); |
181 | reaction = allow; | |
182 | break; | |
183 | case kIOMessageSystemHasPoweredOn: | |
fa7225c8 | 184 | secnotice("powerwatch", "system has powered on"); |
b1ab9ed8 A |
185 | me->systemIsWaking(); |
186 | reaction = ignore; | |
187 | break; | |
188 | case kIOMessageSystemWillPowerOff: | |
fa7225c8 | 189 | secnotice("powerwatch", "system will power off"); |
b1ab9ed8 A |
190 | me->systemWillPowerDown(); |
191 | reaction = allow; | |
192 | break; | |
193 | case kIOMessageSystemWillNotPowerOff: | |
fa7225c8 | 194 | secnotice("powerwatch", "system will not power off"); |
b1ab9ed8 A |
195 | reaction = ignore; |
196 | break; | |
197 | case kIOMessageCanSystemSleep: | |
fa7225c8 | 198 | secnotice("powerwatch", "can system sleep"); |
b1ab9ed8 A |
199 | reaction = allow; |
200 | break; | |
201 | case kIOMessageSystemWillNotSleep: | |
fa7225c8 | 202 | secnotice("powerwatch", "system will not sleep"); |
b1ab9ed8 A |
203 | reaction = ignore; |
204 | break; | |
205 | case kIOMessageCanSystemPowerOff: | |
fa7225c8 | 206 | secnotice("powerwatch", "can system power off"); |
b1ab9ed8 A |
207 | reaction = allow; |
208 | break; | |
209 | case kIOMessageSystemWillPowerOn: | |
fa7225c8 | 210 | secnotice("powerwatch", "system will power on"); |
b1ab9ed8 A |
211 | me->systemWillPowerOn(); |
212 | reaction = ignore; | |
213 | break; | |
214 | default: | |
fa7225c8 | 215 | secnotice("powerwatch", |
b1ab9ed8 A |
216 | "type 0x%x message received (ignored)", messageType); |
217 | reaction = ignore; | |
218 | break; | |
219 | } | |
220 | ||
221 | // handle acknowledgments | |
222 | switch (reaction) { | |
223 | case allow: | |
fa7225c8 | 224 | secnotice("powerwatch", "calling IOAllowPowerChange"); |
b1ab9ed8 A |
225 | IOAllowPowerChange(me->mKernelPort, long(argument)); |
226 | break; | |
227 | case refuse: | |
fa7225c8 | 228 | secnotice("powerwatch", "calling IOCancelPowerChange"); |
b1ab9ed8 A |
229 | IOCancelPowerChange(me->mKernelPort, long(argument)); |
230 | break; | |
231 | case ignore: | |
fa7225c8 | 232 | secnotice("powerwatch", "sending no response"); |
b1ab9ed8 A |
233 | break; |
234 | } | |
235 | } | |
236 | ||
237 | ||
238 | // | |
239 | // The MachServer hookup | |
240 | // | |
241 | PortPowerWatcher::PortPowerWatcher() | |
242 | { | |
243 | port(IONotificationPortGetMachPort(mPortRef)); | |
244 | } | |
245 | ||
246 | boolean_t PortPowerWatcher::handle(mach_msg_header_t *in) | |
247 | { | |
248 | IODispatchCalloutFromMessage(NULL, in, mPortRef); | |
249 | return TRUE; | |
250 | } | |
251 | ||
252 | ||
253 | } // end namespace MachPlusPlus | |
254 | ||
255 | } // end namespace Security | |
866f8763 A |
256 | |
257 | #endif //TARGET_OS_OSX |