X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_utilities/lib/powerwatch.cpp diff --git a/libsecurity_utilities/lib/powerwatch.cpp b/libsecurity_utilities/lib/powerwatch.cpp new file mode 100644 index 00000000..f1ab9524 --- /dev/null +++ b/libsecurity_utilities/lib/powerwatch.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// powerwatch - hook into system notifications of power events +// +#include "powerwatch.h" +#include + + +namespace Security { +namespace MachPlusPlus { + + +// +// The obligatory empty virtual destructor +// +PowerWatcher::~PowerWatcher() +{ } + + +// +// The default NULL implementations of the callback virtuals. +// We define these (rather than leaving them abstract) since +// many users want only one of these events. +// +void PowerWatcher::systemWillSleep() +{ } + +void PowerWatcher::systemIsWaking() +{ } + +void PowerWatcher::systemWillPowerDown() +{ } + +void PowerWatcher::systemWillPowerOn() +{ } + +// +// IOPowerWatchers +// + +void +IOPowerWatcher::iopmcallback(void * param, + IOPMConnection connection, + IOPMConnectionMessageToken token, + IOPMSystemPowerStateCapabilities capabilities) +{ + IOPowerWatcher *me = (IOPowerWatcher *)param; + + if (SECURITY_DEBUG_LOG_ENABLED()) { + secdebug("powerwatch", "powerstates"); + if (capabilities & kIOPMSystemPowerStateCapabilityDisk) + secdebug("powerwatch", "disk"); + if (capabilities & kIOPMSystemPowerStateCapabilityNetwork) + secdebug("powerwatch", "net"); + if (capabilities & kIOPMSystemPowerStateCapabilityAudio) + secdebug("powerwatch", "audio"); + if (capabilities & kIOPMSystemPowerStateCapabilityVideo) + secdebug("powerwatch", "video"); + } + + /* if cpu and no display -> in DarkWake */ + if ((capabilities & (kIOPMSystemPowerStateCapabilityCPU|kIOPMSystemPowerStateCapabilityVideo)) == kIOPMSystemPowerStateCapabilityCPU) { + secdebug("powerwatch", "enter DarkWake"); + me->mInDarkWake = true; + } else if (me->mInDarkWake) { + secdebug("powerwatch", "exit DarkWake"); + me->mInDarkWake = false; + } + + (void)IOPMConnectionAcknowledgeEvent(connection, token); + + return; +} + + +void +IOPowerWatcher::setupDarkWake() +{ + IOReturn ret; + + mInDarkWake = false; + + mIOPMqueue = dispatch_queue_create("com.apple.security.IOPowerWatcher", NULL); + if (mIOPMqueue == NULL) + return; + + ret = ::IOPMConnectionCreate(CFSTR("IOPowerWatcher"), + kIOPMSystemPowerStateCapabilityDisk + | kIOPMSystemPowerStateCapabilityNetwork + | kIOPMSystemPowerStateCapabilityAudio + | kIOPMSystemPowerStateCapabilityVideo, + &mIOPMconn); + if (ret != kIOReturnSuccess) + return; + + ret = ::IOPMConnectionSetNotification(mIOPMconn, this, + (IOPMEventHandlerType)iopmcallback); + if (ret != kIOReturnSuccess) + return; + + ::IOPMConnectionSetDispatchQueue(mIOPMconn, mIOPMqueue); +} + +IOPowerWatcher::IOPowerWatcher() +{ + if (!(mKernelPort = ::IORegisterForSystemPower(this, &mPortRef, ioCallback, &mHandle))) + UnixError::throwMe(EINVAL); // no clue + + setupDarkWake(); +} + +IOPowerWatcher::~IOPowerWatcher() +{ + if (mKernelPort) + ::IODeregisterForSystemPower(&mHandle); + + if (mIOPMconn) { + ::IOPMConnectionSetDispatchQueue(mIOPMconn, NULL); + ::IOPMConnectionRelease(mIOPMconn); + } + if (mIOPMqueue) + ::dispatch_release(mIOPMqueue); +} + + +// +// The callback dispatcher +// +void IOPowerWatcher::ioCallback(void *refCon, io_service_t service, + natural_t messageType, void *argument) +{ + IOPowerWatcher *me = (IOPowerWatcher *)refCon; + enum { allow, refuse, ignore } reaction; + switch (messageType) { + case kIOMessageSystemWillSleep: + secdebug("powerwatch", "system will sleep"); + me->systemWillSleep(); + reaction = allow; + break; + case kIOMessageSystemHasPoweredOn: + secdebug("powerwatch", "system has powered on"); + me->systemIsWaking(); + reaction = ignore; + break; + case kIOMessageSystemWillPowerOff: + secdebug("powerwatch", "system will power off"); + me->systemWillPowerDown(); + reaction = allow; + break; + case kIOMessageSystemWillNotPowerOff: + secdebug("powerwatch", "system will not power off"); + reaction = ignore; + break; + case kIOMessageCanSystemSleep: + secdebug("powerwatch", "can system sleep"); + reaction = allow; + break; + case kIOMessageSystemWillNotSleep: + secdebug("powerwatch", "system will not sleep"); + reaction = ignore; + break; + case kIOMessageCanSystemPowerOff: + secdebug("powerwatch", "can system power off"); + reaction = allow; + break; + case kIOMessageSystemWillPowerOn: + secdebug("powerwatch", "system will power on"); + me->systemWillPowerOn(); + reaction = ignore; + break; + default: + secdebug("powerwatch", + "type 0x%x message received (ignored)", messageType); + reaction = ignore; + break; + } + + // handle acknowledgments + switch (reaction) { + case allow: + secdebug("powerwatch", "calling IOAllowPowerChange"); + IOAllowPowerChange(me->mKernelPort, long(argument)); + break; + case refuse: + secdebug("powerwatch", "calling IOCancelPowerChange"); + IOCancelPowerChange(me->mKernelPort, long(argument)); + break; + case ignore: + secdebug("powerwatch", "sending no response"); + break; + } +} + + +// +// The MachServer hookup +// +PortPowerWatcher::PortPowerWatcher() +{ + port(IONotificationPortGetMachPort(mPortRef)); +} + +boolean_t PortPowerWatcher::handle(mach_msg_header_t *in) +{ + IODispatchCalloutFromMessage(NULL, in, mPortRef); + return TRUE; +} + + +} // end namespace MachPlusPlus + +} // end namespace Security