]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_utilities/lib/powerwatch.cpp
Security-58286.270.3.0.1.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / powerwatch.cpp
CommitLineData
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
33namespace Security {
34namespace MachPlusPlus {
35
36
37//
38// The obligatory empty virtual destructor
39//
40PowerWatcher::~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//
49void PowerWatcher::systemWillSleep()
50{ }
51
52void PowerWatcher::systemIsWaking()
53{ }
54
55void PowerWatcher::systemWillPowerDown()
56{ }
57
58void PowerWatcher::systemWillPowerOn()
59{ }
60
61//
62// IOPowerWatchers
63//
64
65void
66IOPowerWatcher::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
98void
99IOPowerWatcher::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
128IOPowerWatcher::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
146IOPowerWatcher::~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//
172void 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//
241PortPowerWatcher::PortPowerWatcher()
242{
243 port(IONotificationPortGetMachPort(mPortRef));
244}
245
246boolean_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