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         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"); 
  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; 
  91     (void)IOPMConnectionAcknowledgeEvent(connection
, token
); 
  98 IOPowerWatcher::setupDarkWake() 
 104     ret 
= ::IOPMConnectionCreate(CFSTR("IOPowerWatcher"), 
 105                                  kIOPMSystemPowerStateCapabilityDisk 
 
 106                                  | kIOPMSystemPowerStateCapabilityNetwork
 
 107                                  | kIOPMSystemPowerStateCapabilityAudio 
 
 108                                  | kIOPMSystemPowerStateCapabilityVideo
, 
 110     if (ret 
== kIOReturnSuccess
) { 
 111         ret 
= ::IOPMConnectionSetNotification(mIOPMconn
, this, 
 112                           (IOPMEventHandlerType
)iopmcallback
); 
 113         if (ret 
== kIOReturnSuccess
) { 
 114             ::IOPMConnectionSetDispatchQueue(mIOPMconn
, mIOPMqueue
); 
 118     mUserActiveHandle 
= IOPMScheduleUserActiveChangedNotification(mIOPMqueue
, ^(bool active
) { 
 124     dispatch_group_leave(mDarkWakeGroup
); 
 127 IOPowerWatcher::IOPowerWatcher() : 
 128     mKernelPort(0), mIOPMconn(NULL
), mIOPMqueue(NULL
), mDarkWakeGroup(NULL
), mUserActiveHandle(NULL
) 
 130         if (!(mKernelPort 
= ::IORegisterForSystemPower(this, &mPortRef
, ioCallback
, &mHandle
))) 
 131                 UnixError::throwMe(EINVAL
);     // no clue 
 133         mIOPMqueue 
= dispatch_queue_create("com.apple.security.IOPowerWatcher", NULL
); 
 134         if (mIOPMqueue 
== NULL
) 
 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(); }); 
 145 IOPowerWatcher::~IOPowerWatcher() 
 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
); 
 154                 ::IODeregisterForSystemPower(&mHandle
); 
 157                 ::IOPMConnectionSetDispatchQueue(mIOPMconn
, NULL
); 
 158                 ::IOPMConnectionRelease(mIOPMconn
); 
 160         if (mUserActiveHandle
) 
 161                 ::IOPMUnregisterNotification(mUserActiveHandle
); 
 163                 ::dispatch_release(mIOPMqueue
); 
 169 // The callback dispatcher 
 171 void IOPowerWatcher::ioCallback(void *refCon
, io_service_t service
, 
 172     natural_t messageType
, void *argument
) 
 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(); 
 182     case kIOMessageSystemHasPoweredOn
: 
 183         secnotice("powerwatch", "system has powered on"); 
 184         me
->systemIsWaking(); 
 187     case kIOMessageSystemWillPowerOff
: 
 188         secnotice("powerwatch", "system will power off"); 
 189         me
->systemWillPowerDown(); 
 192     case kIOMessageSystemWillNotPowerOff
: 
 193         secnotice("powerwatch", "system will not power off"); 
 196     case kIOMessageCanSystemSleep
: 
 197         secnotice("powerwatch", "can system sleep"); 
 200     case kIOMessageSystemWillNotSleep
: 
 201         secnotice("powerwatch", "system will not sleep"); 
 204     case kIOMessageCanSystemPowerOff
: 
 205         secnotice("powerwatch", "can system power off"); 
 208         case kIOMessageSystemWillPowerOn
: 
 209         secnotice("powerwatch", "system will power on"); 
 210                 me
->systemWillPowerOn(); 
 214         secnotice("powerwatch", 
 215             "type 0x%x message received (ignored)", messageType
); 
 220     // handle acknowledgments 
 223                 secnotice("powerwatch", "calling IOAllowPowerChange"); 
 224         IOAllowPowerChange(me
->mKernelPort
, long(argument
)); 
 227                 secnotice("powerwatch", "calling IOCancelPowerChange"); 
 228         IOCancelPowerChange(me
->mKernelPort
, long(argument
)); 
 231                 secnotice("powerwatch", "sending no response"); 
 238 // The MachServer hookup 
 240 PortPowerWatcher::PortPowerWatcher() 
 242     port(IONotificationPortGetMachPort(mPortRef
)); 
 245 boolean_t 
PortPowerWatcher::handle(mach_msg_header_t 
*in
) 
 247     IODispatchCalloutFromMessage(NULL
, in
, mPortRef
); 
 252 } // end namespace MachPlusPlus 
 254 } // end namespace Security