]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/powerwatch.cpp
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / powerwatch.cpp
1 /*
2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
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
31
32 namespace Security {
33 namespace MachPlusPlus {
34
35
36 //
37 // The obligatory empty virtual destructor
38 //
39 PowerWatcher::~PowerWatcher()
40 { }
41
42
43 //
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.
47 //
48 void PowerWatcher::systemWillSleep()
49 { }
50
51 void PowerWatcher::systemIsWaking()
52 { }
53
54 void PowerWatcher::systemWillPowerDown()
55 { }
56
57 void PowerWatcher::systemWillPowerOn()
58 { }
59
60 //
61 // IOPowerWatchers
62 //
63
64 void
65 IOPowerWatcher::iopmcallback(void * param,
66 IOPMConnection connection,
67 IOPMConnectionMessageToken token,
68 IOPMSystemPowerStateCapabilities capabilities)
69 {
70 IOPowerWatcher *me = (IOPowerWatcher *)param;
71
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");
81
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;
89 }
90
91 (void)IOPMConnectionAcknowledgeEvent(connection, token);
92
93 return;
94 }
95
96
97 void
98 IOPowerWatcher::setupDarkWake()
99 {
100 IOReturn ret;
101
102 mInDarkWake = false;
103
104 ret = ::IOPMConnectionCreate(CFSTR("IOPowerWatcher"),
105 kIOPMSystemPowerStateCapabilityDisk
106 | kIOPMSystemPowerStateCapabilityNetwork
107 | kIOPMSystemPowerStateCapabilityAudio
108 | kIOPMSystemPowerStateCapabilityVideo,
109 &mIOPMconn);
110 if (ret == kIOReturnSuccess) {
111 ret = ::IOPMConnectionSetNotification(mIOPMconn, this,
112 (IOPMEventHandlerType)iopmcallback);
113 if (ret == kIOReturnSuccess) {
114 ::IOPMConnectionSetDispatchQueue(mIOPMconn, mIOPMqueue);
115 }
116 }
117
118 mUserActiveHandle = IOPMScheduleUserActiveChangedNotification(mIOPMqueue, ^(bool active) {
119 if (active) {
120 mInDarkWake = false;
121 }
122 });
123
124 dispatch_group_leave(mDarkWakeGroup);
125 }
126
127 IOPowerWatcher::IOPowerWatcher() :
128 mKernelPort(0), mIOPMconn(NULL), mIOPMqueue(NULL), mDarkWakeGroup(NULL), mUserActiveHandle(NULL)
129 {
130 if (!(mKernelPort = ::IORegisterForSystemPower(this, &mPortRef, ioCallback, &mHandle)))
131 UnixError::throwMe(EINVAL); // no clue
132
133 mIOPMqueue = dispatch_queue_create("com.apple.security.IOPowerWatcher", NULL);
134 if (mIOPMqueue == NULL)
135 return;
136
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(); });
143 }
144
145 IOPowerWatcher::~IOPowerWatcher()
146 {
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);
152 }
153 if (mKernelPort)
154 ::IODeregisterForSystemPower(&mHandle);
155
156 if (mIOPMconn) {
157 ::IOPMConnectionSetDispatchQueue(mIOPMconn, NULL);
158 ::IOPMConnectionRelease(mIOPMconn);
159 }
160 if (mUserActiveHandle)
161 ::IOPMUnregisterNotification(mUserActiveHandle);
162 if (mIOPMqueue)
163 ::dispatch_release(mIOPMqueue);
164
165 }
166
167
168 //
169 // The callback dispatcher
170 //
171 void IOPowerWatcher::ioCallback(void *refCon, io_service_t service,
172 natural_t messageType, void *argument)
173 {
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();
180 reaction = allow;
181 break;
182 case kIOMessageSystemHasPoweredOn:
183 secnotice("powerwatch", "system has powered on");
184 me->systemIsWaking();
185 reaction = ignore;
186 break;
187 case kIOMessageSystemWillPowerOff:
188 secnotice("powerwatch", "system will power off");
189 me->systemWillPowerDown();
190 reaction = allow;
191 break;
192 case kIOMessageSystemWillNotPowerOff:
193 secnotice("powerwatch", "system will not power off");
194 reaction = ignore;
195 break;
196 case kIOMessageCanSystemSleep:
197 secnotice("powerwatch", "can system sleep");
198 reaction = allow;
199 break;
200 case kIOMessageSystemWillNotSleep:
201 secnotice("powerwatch", "system will not sleep");
202 reaction = ignore;
203 break;
204 case kIOMessageCanSystemPowerOff:
205 secnotice("powerwatch", "can system power off");
206 reaction = allow;
207 break;
208 case kIOMessageSystemWillPowerOn:
209 secnotice("powerwatch", "system will power on");
210 me->systemWillPowerOn();
211 reaction = ignore;
212 break;
213 default:
214 secnotice("powerwatch",
215 "type 0x%x message received (ignored)", messageType);
216 reaction = ignore;
217 break;
218 }
219
220 // handle acknowledgments
221 switch (reaction) {
222 case allow:
223 secnotice("powerwatch", "calling IOAllowPowerChange");
224 IOAllowPowerChange(me->mKernelPort, long(argument));
225 break;
226 case refuse:
227 secnotice("powerwatch", "calling IOCancelPowerChange");
228 IOCancelPowerChange(me->mKernelPort, long(argument));
229 break;
230 case ignore:
231 secnotice("powerwatch", "sending no response");
232 break;
233 }
234 }
235
236
237 //
238 // The MachServer hookup
239 //
240 PortPowerWatcher::PortPowerWatcher()
241 {
242 port(IONotificationPortGetMachPort(mPortRef));
243 }
244
245 boolean_t PortPowerWatcher::handle(mach_msg_header_t *in)
246 {
247 IODispatchCalloutFromMessage(NULL, in, mPortRef);
248 return TRUE;
249 }
250
251
252 } // end namespace MachPlusPlus
253
254 } // end namespace Security