#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/sysctl.h>
#include <sys/mount.h>
#include <unistd.h>
#include <dlfcn.h>
#include <IOKit/pwr_mgt/IOPMLibPrivate.h>
#include <IOKit/IOHibernatePrivate.h>
#include <pthread.h>
#include "PMSettings.h"
#include "PrivateLib.h"
#include "PMStore.h"
#include "PMAssertions.h"
enum {
kIOPMUnabridgedSettings = false,
kIOPMRemoveUnsupportedSettings = true
};
static CFDictionaryRef energySettings = NULL;
static CFStringRef currentPowerSource = NULL;
static unsigned long g_overrides = 0;
static unsigned long gLastOverrideState = 0;
static long gSleepSetting = -1;
static io_connect_t gPowerManager;
static unsigned long deferredPSChangeNotify = 0;
static unsigned long _pmcfgd_impendingSleep = 0;
static int gSilentRunningOverride = kPMSROverrideNotSet;
static CFDictionaryRef _copyPMSettings(bool removeUnsupported);
static IOReturn activate_profiles(
CFDictionaryRef d,
CFStringRef s,
bool removeUnsupported);
__private_extern__ void overrideSetting
(
int bit,
int val
)
{
if(val) {
g_overrides |= bit;
} else {
g_overrides &= ~bit;
}
}
__private_extern__ bool
GetPMSettingBool(CFStringRef which)
{
CFDictionaryRef current_settings;
CFNumberRef n;
int nint = 0;
CFStringRef pwrSrc;
if (!energySettings || !which)
return false;
if (CFEqual(which, CFSTR(kIOPMDarkWakeBackgroundTaskKey))) {
if (gSilentRunningOverride == kPMSROverrideEnable)
return true;
if (gSilentRunningOverride == kPMSROverrideDisable)
return false;
}
if (_getPowerSource() == kBatteryPowered)
pwrSrc = CFSTR(kIOPMBatteryPowerKey);
else
pwrSrc = CFSTR(kIOPMACPowerKey);
current_settings = (CFDictionaryRef)isA_CFDictionary(
CFDictionaryGetValue(energySettings, pwrSrc));
if (current_settings) {
n = CFDictionaryGetValue(current_settings, which);
if (n) {
CFNumberGetValue(n, kCFNumberIntType, &nint);
}
return (0 != nint);
}
return false;
}
__private_extern__ IOReturn
getDisplaySleepTimer(uint32_t *displaySleepTimer)
{
CFDictionaryRef current_settings;
if (!energySettings || !displaySleepTimer)
return kIOReturnError;
current_settings = (CFDictionaryRef)isA_CFDictionary(
CFDictionaryGetValue(energySettings, currentPowerSource));
if (getAggressivenessValue(current_settings, CFSTR(kIOPMDisplaySleepKey),
kCFNumberSInt32Type, displaySleepTimer) ) {
return kIOReturnSuccess;
}
return kIOReturnError;
}
__private_extern__ void
activateSettingOverrides(void)
{
if (!energySettings)
return;
if (gLastOverrideState != g_overrides)
{
if ((kPMPreventIdleSleep == (gLastOverrideState ^ g_overrides))
&& (-1 != gSleepSetting)) do
{
static io_connect_t gIOPMConnection = MACH_PORT_NULL;
IOReturn kr;
if (!gIOPMConnection) gIOPMConnection = IOPMFindPowerManagement(0);
if (!gIOPMConnection) break;
kr = IOPMSetAggressiveness(gIOPMConnection, kPMMinutesToSleep,
(kPMPreventIdleSleep & g_overrides) ? 0 : gSleepSetting);
if (kIOReturnSuccess != kr)
{
gIOPMConnection = MACH_PORT_NULL;
break;
}
gLastOverrideState = g_overrides;
return;
}
while (false);
gLastOverrideState = g_overrides;
activate_profiles( energySettings,
currentPowerSource,
kIOPMRemoveUnsupportedSettings);
}
}
__private_extern__ void
PMSettingsSleepWakeNotification(natural_t messageType)
{
switch (messageType) {
case kIOMessageSystemWillSleep:
_pmcfgd_impendingSleep = 1;
break;
case kIOMessageSystemHasPoweredOn:
_pmcfgd_impendingSleep = 0;
if(deferredPSChangeNotify)
{
deferredPSChangeNotify = 0;
_pmcfgd_impendingSleep = 0;
if(currentPowerSource && CFEqual(currentPowerSource, CFSTR(kIOPMACPowerKey)))
{
IOPMSetAggressiveness(gPowerManager, kPMPowerSource, kIOPMExternalPower);
} else {
IOPMSetAggressiveness(gPowerManager, kPMPowerSource, kIOPMInternalPower);
}
}
break;
}
return;
}
__private_extern__ CFDictionaryRef
PMSettings_CopyActivePMSettings(void)
{
CFDictionaryRef copy_all_settings;
CFDictionaryRef energySettings;
CFDictionaryRef return_val;
copy_all_settings = _copyPMSettings(kIOPMRemoveUnsupportedSettings);
if(!copy_all_settings) return NULL;
energySettings = isA_CFDictionary(CFDictionaryGetValue(copy_all_settings,currentPowerSource));
if(energySettings)
return_val = CFDictionaryCreateCopy(kCFAllocatorDefault, energySettings);
else
return_val = NULL;
CFRelease(copy_all_settings);
return return_val;
}
__private_extern__ int _get_SR_Override()
{
return gSilentRunningOverride;
}
__private_extern__ void
_Set_SR_override(int override)
{
if (gSilentRunningOverride != override)
{
gSilentRunningOverride = override;
configAssertionType(kBackgroundTaskIndex, false);
}
}
__private_extern__ bool
_DWBT_allowed(void)
{
#if TARGET_OS_EMBEDDED
return false;
#else
return ( (GetPMSettingBool(CFSTR(kIOPMDarkWakeBackgroundTaskKey))) &&
(kACPowered == _getPowerSource()) );
#endif
}
__private_extern__ bool _SS_allowed(void)
{
#if TARGET_OS_EMBEDDED
return false;
#else
if (_DWBT_allowed())
return true;
return ( (GetPMSettingBool(CFSTR(kIOPMDarkWakeBackgroundTaskKey))) &&
(kBatteryPowered == _getPowerSource()) );
#endif
}
static CFDictionaryRef
_copyPMSettings(bool removeUnsupported)
{
if(removeUnsupported) {
return IOPMCopyActivePMPreferences();
} else {
return IOPMCopyUnabridgedActivePMPreferences();
}
}
static IOReturn
activate_profiles(CFDictionaryRef d, CFStringRef s, bool removeUnsupported)
{
CFDictionaryRef energy_settings;
CFDictionaryRef activePMPrefs = NULL;
CFMutableDictionaryRef profiles_activated;
IOReturn ret;
CFNumberRef n1, n0;
CFNumberRef sleepSetting;
int one = 1;
int zero = 0;
if(NULL == d) {
return kIOReturnBadArgument;
}
if(NULL == s) {
s = CFSTR(kIOPMACPowerKey);
}
energy_settings = (CFDictionaryRef)isA_CFDictionary(CFDictionaryGetValue(d, s));
if (!energy_settings) {
return kIOReturnError;
}
sleepSetting = (CFNumberRef)isA_CFNumber(CFDictionaryGetValue(energy_settings, CFSTR(kIOPMSystemSleepKey)));
if (sleepSetting) {
CFNumberGetValue(sleepSetting, kCFNumberLongType, &gSleepSetting);
}
if(g_overrides)
{
profiles_activated = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
CFDictionaryGetCount(energy_settings), energy_settings);
if(!profiles_activated)
return kIOReturnError;
n1 = CFNumberCreate(0, kCFNumberIntType, &one);
n0 = CFNumberCreate(0, kCFNumberIntType, &zero);
if(g_overrides & kPMForceLowSpeedProfile)
{
if(n1) CFDictionarySetValue(profiles_activated, CFSTR(kIOPMReduceSpeedKey), n1);
}
if(g_overrides & kPMForceHighSpeed)
{
if(n0) CFDictionarySetValue(profiles_activated, CFSTR(kIOPMReduceSpeedKey), n0);
if(n0) CFDictionarySetValue(profiles_activated, CFSTR(kIOPMDynamicPowerStepKey), n0);
}
if(g_overrides & kPMPreventIdleSleep)
{
if(n0) CFDictionarySetValue(profiles_activated, CFSTR(kIOPMSystemSleepKey), n0);
}
if(g_overrides & kPMPreventDisplaySleep)
{
if(n0) CFDictionarySetValue(profiles_activated, CFSTR(kIOPMDisplaySleepKey), n0);
}
if (n0)
CFRelease(n0);
if (n1)
CFRelease(n1);
ret = ActivatePMSettings(profiles_activated, removeUnsupported);
CFRelease(profiles_activated);
} else {
ret = ActivatePMSettings(energy_settings, removeUnsupported);
}
activePMPrefs = SCDynamicStoreCopyValue(_getSharedPMDynamicStore(),
CFSTR(kIOPMDynamicStoreSettingsKey));
if( !isA_CFDictionary(activePMPrefs) || !CFEqual(activePMPrefs, energy_settings) )
{
PMStoreSetValue(CFSTR(kIOPMDynamicStoreSettingsKey), energy_settings);
}
if (activePMPrefs)
CFRelease(activePMPrefs);
return ret;
}
__private_extern__ void PMSettings_prime(void)
{
CFTypeRef ps_blob;
gPowerManager = IOPMFindPowerManagement(MACH_PORT_NULL);
if (gPowerManager == 0) return;
IOPMActivateSystemPowerSettings();
ps_blob = IOPSCopyPowerSourcesInfo();
if(ps_blob)
{
currentPowerSource = IOPSGetProvidingPowerSourceType(ps_blob);
CFRelease(ps_blob);
} else currentPowerSource = CFSTR(kIOPMACPowerKey);
energySettings = _copyPMSettings(kIOPMRemoveUnsupportedSettings);
if(energySettings) {
activate_profiles( energySettings,
currentPowerSource,
kIOPMRemoveUnsupportedSettings);
}
if(CFEqual(currentPowerSource, CFSTR(kIOPMACPowerKey)))
IOPMSetAggressiveness(gPowerManager, kPMPowerSource, kIOPMExternalPower);
else IOPMSetAggressiveness(gPowerManager, kPMPowerSource, kIOPMInternalPower);
}
__private_extern__ void
PMSettingsSupportedPrefsListHasChanged(void)
{
PMSettingsPrefsHaveChanged();
}
__private_extern__ void
PMSettingsPrefsHaveChanged(void)
{
IOPMActivateSystemPowerSettings();
if(energySettings) CFRelease(energySettings);
energySettings = isA_CFDictionary(_copyPMSettings(
kIOPMRemoveUnsupportedSettings));
if(energySettings) {
activate_profiles(energySettings,
currentPowerSource,
kIOPMRemoveUnsupportedSettings);
}
return;
}
__private_extern__ void PMSettingsPSChange(CFTypeRef ps_blob)
{
CFStringRef newPowerSource;
newPowerSource = IOPSGetProvidingPowerSourceType(ps_blob);
if(!CFEqual(currentPowerSource, newPowerSource))
{
currentPowerSource = newPowerSource;
if(!_pmcfgd_impendingSleep)
{
if(CFEqual(CFSTR(kIOPMACPowerKey), currentPowerSource))
{
IOPMSetAggressiveness(gPowerManager, kPMPowerSource, kIOPMExternalPower);
} else {
IOPMSetAggressiveness(gPowerManager, kPMPowerSource, kIOPMInternalPower);
}
} else {
deferredPSChangeNotify = 1;
}
if(energySettings) {
activate_profiles( energySettings,
currentPowerSource,
kIOPMRemoveUnsupportedSettings);
}
}
}
__private_extern__ IOReturn
_activateForcedSettings(CFDictionaryRef forceSettings)
{
return activate_profiles( forceSettings,
currentPowerSource,
kIOPMRemoveUnsupportedSettings);
}