/* * Copyright (c) 2001 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@ */ #include #include #include "IOSystemConfiguration.h" #include #include #include #include #include #include #include #include #include #include #include "IOPMLib.h" #include "IOPMLibPrivate.h" #include "powermanagement.h" #include #include #include #include #include #include #include #include //#include //#include //#include //#include //#include #define kSecondsIn5Years 157680000 typedef struct { const char *keyName; uint32_t defaultValueAC; uint32_t defaultValueBattery; } PMSettingDescriptorStruct; #ifndef kIOPMAutoPowerOffEnabledKey #define kIOPMAutoPowerOffEnabledKey "poweroffenabled" #define kIOPMAutoPowerOffDelayKey "poweroffdelay" #endif PMSettingDescriptorStruct defaultSettings[] = { /* Setting Name AC - Battery */ {kIOPMDisplaySleepKey, 5, 5}, {kIOPMDiskSleepKey, 10, 5}, {kIOPMSystemSleepKey, 10, 5}, {kIOPMWakeOnLANKey, 0, 0}, {kIOPMWakeOnRingKey, 0, 0}, {kIOPMRestartOnPowerLossKey, 0, 0}, {kIOPMWakeOnACChangeKey, 0, 0}, {kIOPMSleepOnPowerButtonKey, 1, 0}, {kIOPMWakeOnClamshellKey, 1, 1}, {kIOPMReduceBrightnessKey, 0, 1}, {kIOPMDisplaySleepUsesDimKey, 1, 1}, {kIOPMMobileMotionModuleKey, 1, 1}, {kIOPMTTYSPreventSleepKey, 1, 1}, {kIOPMGPUSwitchKey, 0, 1}, {kIOPMPrioritizeNetworkReachabilityOverSleepKey, 0, 0}, {kIOPMDeepSleepEnabledKey, 0, 0}, {kIOPMDeepSleepDelayKey, 0, 0}, {kIOPMDarkWakeBackgroundTaskKey, 1, 0}, {kIOPMAutoPowerOffEnabledKey, 0, 0}, {kIOPMAutoPowerOffDelayKey, 0, 0} }; static const int kPMSettingsCount = sizeof(defaultSettings)/sizeof(PMSettingDescriptorStruct); /* com.apple.PowerManagement.plist general keys */ #define kIOPMPrefsPath CFSTR("com.apple.PowerManagement.xml") #define kIOPMAppName CFSTR("PowerManagement configd") #define kIOPMSystemPowerKey CFSTR("SystemPowerSettings") #define kIOPMCustomProfileKey CFSTR("Custom Profile") #define kIOHibernateDefaultFile "/var/vm/sleepimage" #define kIOPMPrefsPath CFSTR("com.apple.PowerManagement.xml") #define kIOPMAppName CFSTR("PowerManagement configd") /* IOPMRootDomain property keys for default settings */ #define kIOPMSystemDefaultProfilesKey "SystemPowerProfiles" #define kIOPMSystemDefaultOverrideKey "SystemPowerProfileOverrideDict" /* Keys for Cheetah Energy Settings shim */ #define kCheetahDimKey CFSTR("MinutesUntilDisplaySleeps") #define kCheetahDiskKey CFSTR("MinutesUntilHardDiskSleeps") #define kCheetahSleepKey CFSTR("MinutesUntilSystemSleeps") #define kCheetahRestartOnPowerLossKey CFSTR("RestartOnPowerLoss") #define kCheetahWakeForNetworkAccessKey CFSTR("WakeForNetworkAdministrativeAccess") #define kCheetahWakeOnRingKey CFSTR("WakeOnRing") // Supported Feature bitfields for IOPMrootDomain Supported Features enum { kIOPMSupportedOnAC = 1<<0, kIOPMSupportedOnBatt = 1<<1, kIOPMSupportedOnUPS = 1<<2 }; /* Power sources * */ #define kPowerSourcesCount 3 #define kPowerProfilesCount 5 enum { kIOPMKeepUnsupportedPreferences = false, kIOPMRemoveUnsupportedPreferences = true }; /* IOPMPrefsNotificationCreateRunLoopSource * user_callback_context supports IOPMPrefsCallback */ typedef struct { IOPMPrefsCallbackType callback; void *context; } user_callback_context; /******************************************************************************/ /******************************************************************************/ /******************************************************************************/ // Forwards static CFStringRef getPowerSourceString(int i); static void mergeUserDefaultOverriddenSettings( CFMutableDictionaryRef es); static int addDefaultEnergySettings( CFMutableDictionaryRef sys ); static void addSystemProfileEnergySettings( CFDictionaryRef user_profile_selections, CFMutableDictionaryRef passed_in); __private_extern__ io_registry_entry_t getPMRootDomainRef(void); static CFStringRef supportedNameForPMName( CFStringRef pm_name ); static bool featureSupportsPowerSource( CFTypeRef featureDetails, CFStringRef power_source); static void IOPMRemoveIrrelevantProperties( CFMutableDictionaryRef energyPrefs); static int getCheetahPumaEnergySettings( CFMutableDictionaryRef energyPrefs); #define kOverWriteDuplicates true #define kKeepOriginalValues false static void mergeDictIntoMutable( CFMutableDictionaryRef target, CFDictionaryRef overrides, bool overwrite); static CFDictionaryRef _copyActivePMPreferences( bool removeUnsupportedSettings); static CFArrayRef _copySystemProvidedProfiles(void); static CFArrayRef _createDefaultSystemProfiles(void); static CFDictionaryRef _createDefaultProfileSelections(void); static CFDictionaryRef _createAllCustomProfileSelections(void); static int _isActiveProfileDictValid( CFDictionaryRef p ); static void _purgeUnsupportedPowerSources( CFMutableDictionaryRef p ); static void ioCallout( SCDynamicStoreRef store __unused, CFArrayRef keys __unused, void *ctxt); static IOReturn readAllPMPlistSettings( bool removeUnsupportedSettings, CFMutableDictionaryRef *customSettings, CFDictionaryRef *profileSelections, bool *defaultSettings); IOReturn _pm_connect(mach_port_t *newConnection); IOReturn _pm_disconnect(mach_port_t connection); /******************************************************************************/ /******************************************************************************/ /******************************************************************************/ /************************************************** * * Energy Saver Preferences * **************************************************/ CFDictionaryRef IOPMCopyCustomPMPreferences(void) { CFMutableDictionaryRef copiedPMPrefs = NULL; CFDictionaryRef immutableRetPrefs = NULL; /* IOPMCopyCustomPMPreferences returns the same thing IOPMCopyPMPreferences * does. This is the recommended version to use; for clarity. */ copiedPMPrefs = IOPMCopyPMPreferences(); if( copiedPMPrefs ) { // Turn it from mutable to immutable immutableRetPrefs = CFDictionaryCreateCopy( kCFAllocatorDefault, (CFDictionaryRef)copiedPMPrefs ); CFRelease(copiedPMPrefs); return immutableRetPrefs; } else { return NULL; } } /**************************************************/ CFMutableDictionaryRef IOPMCopyPMPreferences(void) { IOReturn ret; CFMutableDictionaryRef settings = NULL; ret = readAllPMPlistSettings( kIOPMRemoveUnsupportedPreferences, &settings, NULL, NULL ); if(kIOReturnSuccess == ret) { return settings; } else { return NULL; } } /**************************************************/ #if !TARGET_OS_IPHONE IOReturn IOPMCopyPMSetting( CFStringRef key, CFStringRef power_source, CFTypeRef *outValue) { CFDictionaryRef ActiveSettings = NULL; CFDictionaryRef perPS = NULL; CFStringRef usePowerSource = power_source; CFTypeRef psblob = NULL; bool supported = false; IOReturn ret; if (!key || !outValue) { ret = kIOReturnBadArgument; goto exit; } *outValue = 0; if (!usePowerSource) { psblob = IOPSCopyPowerSourcesInfo(); if (psblob) { usePowerSource = IOPSGetProvidingPowerSourceType(psblob); } else { usePowerSource = CFSTR(kIOPMACPowerKey); } } supported = IOPMFeatureIsAvailable(key, usePowerSource); if (!supported) { ret = kIOReturnUnsupported; goto exit; } ActiveSettings = _copyActivePMPreferences(true); if (ActiveSettings) { perPS = (CFDictionaryRef)CFDictionaryGetValue( ActiveSettings, usePowerSource); if (perPS) { *outValue = CFDictionaryGetValue(perPS, key); } } if (*outValue) { CFRetain(*outValue); ret = kIOReturnSuccess; } else { ret = kIOReturnNotFound; } if (ActiveSettings) { CFRelease(ActiveSettings); } exit: if (psblob) { CFRelease(psblob); } return ret; } #endif /**************************************************/ CFDictionaryRef IOPMCopyActivePMPreferences(void) { return _copyActivePMPreferences(kIOPMRemoveUnsupportedPreferences); } CFDictionaryRef IOPMCopyUnabridgedActivePMPreferences(void) { return _copyActivePMPreferences(kIOPMKeepUnsupportedPreferences); } static CFDictionaryRef _copyActivePMPreferences( bool removeUnsupportedSettings) { CFDictionaryRef active_profiles = NULL; CFArrayRef system_profiles = NULL; CFMutableDictionaryRef custom_settings = NULL; CFMutableDictionaryRef return_val = NULL; CFStringRef *active_profile_dict_keys = NULL; CFNumberRef *active_profile_dict_values = NULL; IOReturn ret; int ps_count; int i; system_profiles = IOPMCopyPowerProfiles(); if(!system_profiles) { return NULL; } /* Depending on removeUnsupportedSettings argument, * the returned custom_settings dictionary may have * removed the settings lacking hardware support * on this machine */ ret = readAllPMPlistSettings( removeUnsupportedSettings, &custom_settings, &active_profiles, NULL ); if( kIOReturnSuccess != ret ) { goto exit; } if(!active_profiles || !system_profiles || !custom_settings) goto exit; return_val = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ps_count = CFDictionaryGetCount(active_profiles); active_profile_dict_keys = (CFStringRef *)malloc(ps_count*sizeof(CFStringRef)); active_profile_dict_values = (CFNumberRef *)malloc(ps_count*sizeof(CFNumberRef)); if(!active_profile_dict_keys || !active_profile_dict_values) goto exit; CFDictionaryGetKeysAndValues( active_profiles, (const void **)active_profile_dict_keys, (const void **)active_profile_dict_values); for(i=0; i 4) ) continue; sys_profile = isA_CFDictionary( CFArrayGetValueAtIndex(system_profiles, profile_index)); if(!sys_profile) continue; settings_per_power_source = CFDictionaryGetValue(sys_profile, active_profile_dict_keys[i]); } if(!settings_per_power_source) { continue; } tmp_settings = CFDictionaryCreateCopy(kCFAllocatorDefault, settings_per_power_source); if(!tmp_settings) continue; CFDictionarySetValue(return_val, active_profile_dict_keys[i], tmp_settings); CFRelease(tmp_settings); } exit: if(active_profile_dict_keys) free(active_profile_dict_keys); if(active_profile_dict_values) free(active_profile_dict_values); if(active_profiles) CFRelease(active_profiles); if(system_profiles) CFRelease(system_profiles); if(custom_settings) CFRelease(custom_settings); return return_val; } /**************************************************/ // A duplicate function for IOPMSetPMPreferences // Provided as "IOPMSetCustomPMPreferences" for clarity IOReturn IOPMSetCustomPMPreferences(CFDictionaryRef ESPrefs) { return IOPMSetPMPreferences(ESPrefs); } /**************************************************/ IOReturn IOPMRevertPMPreferences(CFArrayRef keys_arr) { IOReturn ret = kIOReturnInternalError; int keys_i = 0; int keys_count = 0; CFStringRef revert_this_setting = NULL; bool these_are_defaults = false; int csi = 0; CFMutableDictionaryRef customSettings = NULL; int customSettingsCount = 0; CFDictionaryRef *customSettingsDicts = NULL; CFStringRef *customSettingsKeys = NULL; readAllPMPlistSettings(kIOPMRemoveUnsupportedPreferences, &customSettings, NULL, &these_are_defaults); if (these_are_defaults) { /* If the system has default settings, then there's nothing * for us to revert to default. Good bye. */ ret = kIOReturnInvalid; goto exit_and_free; } if (!keys_arr || (0 == (keys_count = CFArrayGetCount(keys_arr)))) { /* Revert to OS Defaults * PM tracks your current settings as indices into a now-defunct array of settings, called profiles. * We "revert to defaults" by selecting profiles AC=2, Batt=1, UPS=1 * Note that "custom settings" are AC=-1, Batt=-1, UPS=-1 */ CFDictionaryRef twooneoneprofiles = NULL; CFStringRef tooKeys[kPowerSourcesCount] = { CFSTR(kIOPMACPowerKey), CFSTR(kIOPMBatteryPowerKey), CFSTR(kIOPMUPSPowerKey) }; CFNumberRef tooVals[kPowerSourcesCount]; int setVal = 0; setVal = 2; tooVals[0] = CFNumberCreate(0, kCFNumberIntType, &setVal); setVal = 1; tooVals[1] = CFNumberCreate(0, kCFNumberIntType, &setVal); tooVals[2] = CFNumberCreate(0, kCFNumberIntType, &setVal); twooneoneprofiles = CFDictionaryCreate(0, (const void **)tooKeys, (const void **)tooVals, kPowerSourcesCount, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (twooneoneprofiles) { IOPMSetActivePowerProfiles(twooneoneprofiles); CFRelease(twooneoneprofiles); } CFRelease(tooVals[0]); CFRelease(tooVals[1]); CFRelease(tooVals[2]); ret = kIOReturnSuccess; goto exit_and_free; } customSettingsCount = CFDictionaryGetCount(customSettings); customSettingsKeys = (CFStringRef *)malloc(customSettingsCount * sizeof(CFStringRef)); customSettingsDicts = (CFDictionaryRef *)malloc(customSettingsCount * sizeof(CFDictionaryRef)); CFDictionaryGetKeysAndValues(customSettings, (const void **)customSettingsKeys, (const void **)customSettingsDicts); for (csi=0; csicontext = context; ioContext->callback = callback; // Open connection to SCDynamicStore. User's callback as context. store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("IOKit Preferences Copy"), ioCallout, (void *)&scContext); if(!store) return NULL; // Setup notification for changes in Energy Saver prefences EnergyPrefsKey = SCDynamicStoreKeyCreatePreferences( NULL, kIOPMPrefsPath, kSCPreferencesKeyApply); if(EnergyPrefsKey) { SCDynamicStoreAddWatchedKey(store, EnergyPrefsKey, FALSE); CFRelease(EnergyPrefsKey); } // Obtain the CFRunLoopSourceRef from this SCDynamicStoreRef session SCDrls = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, store, 0); CFRelease(store); return SCDrls; } /******************************************************************************/ /******************************************************************************/ /******************************************************************************/ // Internals static void mergeUserDefaultOverriddenSettings(CFMutableDictionaryRef es) { CFMutableDictionaryRef batt = NULL; CFMutableDictionaryRef ac = NULL; CFMutableDictionaryRef ups = NULL; CFDictionaryRef acOver = NULL; CFDictionaryRef battOver = NULL; CFDictionaryRef upsOver = NULL; SCDynamicStoreRef dynamic_store = NULL; CFDictionaryRef userOverrides = NULL; /* * There might be a CFDictionary in the SCDynamicStore at * "State:/IOKit/PowerManagement/UserOverrides" * == kIOPMDynamicStoreUserOverridesKey * If there is, then we will prefer to use its settings * as default settings, rather than our hard-coded defaults, * for unspecified setting values. */ dynamic_store = SCDynamicStoreCreate(0, CFSTR("IOKit User Library - PM defaults"), NULL, NULL); if (dynamic_store) { userOverrides = SCDynamicStoreCopyValue(dynamic_store, CFSTR(kIOPMDynamicStoreUserOverridesKey)); CFRelease(dynamic_store); } if (NULL == userOverrides) return; if (!isA_CFDictionary(userOverrides)) { CFRelease(userOverrides); return; } acOver = CFDictionaryGetValue(userOverrides, CFSTR(kIOPMACPowerKey)); battOver = CFDictionaryGetValue(userOverrides, CFSTR(kIOPMBatteryPowerKey)); upsOver = CFDictionaryGetValue(userOverrides, CFSTR(kIOPMUPSPowerKey)); // Overrides either contains 3 dictionaries of PM Settings keyed as // AC, Battery, and UPS Power, or it is itself a dictionary of PM Settings. if(acOver && battOver && upsOver) { // Good. All 3 power source settings types are represented. // Do nothing here. } else if(!acOver && !battOver && !upsOver) { // The dictionary didn't specify any per-power source overrides, which // means that it's a flat dictionary strictly of PM settings. // We duplicate it 3 ways, as each overridden setting in this dictionary // will be applied to each power source's settings. acOver = battOver = upsOver = userOverrides; } else { return; } ac = (CFMutableDictionaryRef)CFDictionaryGetValue(es, CFSTR(kIOPMACPowerKey)); batt = (CFMutableDictionaryRef)CFDictionaryGetValue(es, CFSTR(kIOPMBatteryPowerKey)); ups = (CFMutableDictionaryRef)CFDictionaryGetValue(es, CFSTR(kIOPMUPSPowerKey)); if (ac) { mergeDictIntoMutable(ac, acOver, kKeepOriginalValues); } if (batt) { mergeDictIntoMutable(batt, battOver, kKeepOriginalValues); } if (ups) { mergeDictIntoMutable(ups, upsOver, kKeepOriginalValues); } CFRelease (userOverrides); return; } static int addDefaultEnergySettings(CFMutableDictionaryRef sys) { CFMutableDictionaryRef batt = NULL; CFMutableDictionaryRef ac = NULL; CFMutableDictionaryRef ups = NULL; int i; CFNumberRef val; CFStringRef key; batt = (CFMutableDictionaryRef)CFDictionaryGetValue(sys, CFSTR(kIOPMBatteryPowerKey)); ac = (CFMutableDictionaryRef)CFDictionaryGetValue(sys, CFSTR(kIOPMACPowerKey)); ups = (CFMutableDictionaryRef)CFDictionaryGetValue(sys, CFSTR(kIOPMUPSPowerKey)); /* * Note that in the following "poplulation" loops, we're using * CFDictionaryAddValue rather than CFDictionarySetValue. If a value is * already present AddValue will not replace it. */ /* * Populate default battery dictionary */ if (batt) { for (i=0; i kPowerProfilesCount) ) { int_profile_choice = 2; } // Index into systemProfiles at profileNumber profile_at_idx = CFArrayGetValueAtIndex( system_profiles, int_profile_choice); if(!profile_at_idx) continue; // From the profile's CFDictionary, extract the final actual // settings CFDictionary for "this profile number" and for // "this power source" finally_actual_settings = CFDictionaryGetValue( profile_at_idx, this_power_source); // Gently merge this settings CFDictionary into the passed-in // settings dictionary's appropiate power-source specific dictionary ps_passed_in = (CFMutableDictionaryRef) CFDictionaryGetValue(passed_in, this_power_source); if(!finally_actual_settings || !ps_passed_in) continue; mergeDictIntoMutable( ps_passed_in, finally_actual_settings, kKeepOriginalValues); } exit_cleanup: // if(user_profile_selections) CFRelease(user_profile_selections); if(default_profile_selections) CFRelease(default_profile_selections); if(system_profiles) CFRelease(system_profiles); return; } /* getPMRootDomainRef * * Caller should not release the returned io_registry_entry_t */ __private_extern__ io_registry_entry_t getPMRootDomainRef(void) { static io_registry_entry_t cached_root_domain = MACH_PORT_NULL; if( MACH_PORT_NULL == cached_root_domain ) { cached_root_domain = IORegistryEntryFromPath( kIOMasterPortDefault, kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); } return cached_root_domain; } /* Maps a PowerManagement string constant * -> to its corresponding Supported Feature in IOPMrootDomain */ static CFStringRef supportedNameForPMName( CFStringRef pm_name ) { #if TARGET_OS_IPHONE if( CFEqual(pm_name, CFSTR(kIOPMReduceBrightnessKey)) || CFEqual(pm_name, CFSTR(kIOPMDisplaySleepUsesDimKey)) ) #else if(CFEqual(pm_name, CFSTR(kIOPMDisplaySleepUsesDimKey))) #endif /* TARGET_OS_IPHONE */ { return CFSTR("DisplayDims"); } if(CFEqual(pm_name, CFSTR(kIOPMWakeOnLANKey)) || CFEqual(pm_name, CFSTR(kIOPMPrioritizeNetworkReachabilityOverSleepKey))) { return CFSTR("WakeOnMagicPacket"); } if(CFEqual(pm_name, CFSTR(kIOPMMobileMotionModuleKey))) { return CFSTR("MobileMotionModule"); } if( CFEqual(pm_name, CFSTR(kIOHibernateModeKey)) || CFEqual(pm_name, CFSTR(kIOHibernateFreeRatioKey)) || CFEqual(pm_name, CFSTR(kIOHibernateFreeTimeKey)) || CFEqual(pm_name, CFSTR(kIOHibernateFileKey)) || CFEqual(pm_name, CFSTR(kIOHibernateFeatureKey))) { return CFSTR(kIOHibernateFeatureKey); } if (CFEqual(pm_name, CFSTR(kIOPMDeepSleepEnabledKey)) || CFEqual(pm_name, CFSTR(kIOPMDeepSleepDelayKey))) { return CFSTR("DeepSleep"); } if (CFEqual(pm_name, CFSTR(kIOPMAutoPowerOffEnabledKey)) || CFEqual(pm_name, CFSTR(kIOPMAutoPowerOffDelayKey))) { return CFSTR("AutoPowerOff"); } return pm_name; } // Helper for IOPMFeatureIsAvailable static bool featureSupportsPowerSource(CFTypeRef featureDetails, CFStringRef power_source) { CFNumberRef featureNum = NULL; CFNumberRef tempNum = NULL; CFArrayRef featureArr = NULL; uint32_t ps_support = 0; uint32_t tmp; unsigned int i; if( (featureNum = isA_CFNumber(featureDetails)) ) { CFNumberGetValue(featureNum, kCFNumberSInt32Type, &ps_support); } else if( (featureArr = isA_CFArray(featureDetails)) ) { // If several entitites are asserting a given feature, we OR // together their supported power sources. unsigned int arrayCount = CFArrayGetCount(featureArr); for(i = 0; i= 0) { if(kCFBooleanTrue != IOPSPowerSourceSupported(ps_snapshot, profile_keys[profile_count])) { // Remove dictionary if the whole power source isn't supported on this machine. CFDictionaryRemoveValue(energyPrefs, profile_keys[profile_count]); } else { // Make a mutable copy of the prefs dictionary this_profile = (CFMutableDictionaryRef)isA_CFDictionary( CFDictionaryGetValue(energyPrefs, profile_keys[profile_count])); if(!this_profile) continue; this_profile = CFDictionaryCreateMutableCopy(NULL, 0, this_profile); if(!this_profile) continue; CFDictionarySetValue(energyPrefs, profile_keys[profile_count], this_profile); CFRelease(this_profile); // And prune unneeded settings from our new mutable property dict_count = CFDictionaryGetCount(this_profile); dict_keys = (CFStringRef *)malloc(sizeof(CFStringRef) * dict_count); dict_vals = (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef) * dict_count); if (!dict_keys || !dict_vals) continue; CFDictionaryGetKeysAndValues(this_profile, (const void **)dict_keys, (const void **)dict_vals); // For each specific property within each dictionary while(--dict_count >= 0) { if( CFEqual((CFStringRef)dict_keys[dict_count], CFSTR(kIOPMDarkWakeBackgroundTaskKey)) ) { #if !TARGET_OS_IPHONE // We conditionalize PowerNap support on kIOPMPowerNapSupportedKey for all // machines late 2012 and beyond. The presence of this key is a sufficient // condition to support PowerNap bool supportsNewPNKey = false; if(IOPMFeatureIsAvailableWithSupportedTable( CFSTR(kIOPMPowerNapSupportedKey), (CFStringRef)profile_keys[profile_count], _supportedCached)) { supportsNewPNKey = true; } // For legacy machines, we look for either the kIOPMDarkWakeBackgroundTaskKey or the // kIOPMSleepServicesKey if ( ((!IOPMFeatureIsAvailableWithSupportedTable( CFSTR(kIOPMDarkWakeBackgroundTaskKey), (CFStringRef)profile_keys[profile_count], _supportedCached) && !IOPMFeatureIsAvailableWithSupportedTable( CFSTR(kIOPMSleepServicesKey), (CFStringRef)profile_keys[profile_count], _supportedCached)) && !supportsNewPNKey ) { CFDictionaryRemoveValue(this_profile, (CFStringRef)dict_keys[dict_count]); } #endif /* !TARGET_OS_IPHONE */ } else if( !IOPMFeatureIsAvailableWithSupportedTable((CFStringRef)dict_keys[dict_count], (CFStringRef)profile_keys[profile_count], _supportedCached) ) { // If the property isn't supported, remove it CFDictionaryRemoveValue(this_profile, (CFStringRef)dict_keys[dict_count]); } } free(dict_keys); free(dict_vals); } } exit: if (profile_keys) free(profile_keys); if (profile_vals) free(profile_vals); if (ps_snapshot) CFRelease(ps_snapshot); if (_supportedCached) CFRelease(_supportedCached); return; } /*** * getCheetahPumaEnergySettings * * Reads the old Energy Saver preferences file from /Library/Preferences/com.apple.PowerManagement.xml * ***/ static int getCheetahPumaEnergySettings(CFMutableDictionaryRef energyPrefs) { SCPreferencesRef CheetahPrefs = NULL; CFMutableDictionaryRef s = NULL; CFNumberRef n; CFBooleanRef b; if(!energyPrefs) return 0; CheetahPrefs = SCPreferencesCreate (kCFAllocatorDefault, CFSTR("I/O Kit PM Library"), CFSTR("/Library/Preferences/com.apple.PowerManagement.plist")); if(!CheetahPrefs) return 0; s = (CFMutableDictionaryRef)CFDictionaryGetValue( energyPrefs, CFSTR(kIOPMBatteryPowerKey)); if(!s) { CFRelease(CheetahPrefs); return 0; } n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDimKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDisplaySleepKey), n); n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDiskKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDiskSleepKey), n); n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahSleepKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMSystemSleepKey), n); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahRestartOnPowerLossKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMRestartOnPowerLossKey), b); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeForNetworkAccessKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnLANKey), b); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeOnRingKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnRingKey), b); s = (CFMutableDictionaryRef)CFDictionaryGetValue(energyPrefs, CFSTR(kIOPMACPowerKey)); if(!s) { CFRelease(CheetahPrefs); return 0; } n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDimKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDisplaySleepKey), n); n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahDiskKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMDiskSleepKey), n); n = (CFNumberRef)SCPreferencesGetValue(CheetahPrefs, kCheetahSleepKey); if(n) CFDictionaryAddValue(s, CFSTR(kIOPMSystemSleepKey), n); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahRestartOnPowerLossKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMRestartOnPowerLossKey), b); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeForNetworkAccessKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnLANKey), b); b = (CFBooleanRef)SCPreferencesGetValue(CheetahPrefs, kCheetahWakeOnRingKey); if(b) CFDictionaryAddValue(s, CFSTR(kIOPMWakeOnRingKey), b); CFRelease(CheetahPrefs); return 1; // success } /************************************************** * * System Power Settings * **************************************************/ IOReturn IOPMActivateSystemPowerSettings( void ) { io_registry_entry_t rootdomain = MACH_PORT_NULL; CFDictionaryRef settings = NULL; IOReturn ret = kIOReturnSuccess; bool disable_sleep = false; settings = IOPMCopySystemPowerSettings(); if(!settings) { goto exit; } // Disable Sleep? disable_sleep = (kCFBooleanTrue == CFDictionaryGetValue( settings, kIOPMSleepDisabledKey )); rootdomain = getPMRootDomainRef(); ret = IORegistryEntrySetCFProperty( rootdomain, kIOPMSleepDisabledKey, (disable_sleep ? kCFBooleanTrue : kCFBooleanFalse)); #if !TARGET_OS_IPHONE bool avoid_keyStore = false; // Disable FDE Key Store on SMC avoid_keyStore = (kCFBooleanTrue == CFDictionaryGetValue( settings, CFSTR(kIOPMDestroyFVKeyOnStandbyKey) )); ret = IORegistryEntrySetCFProperty( rootdomain, CFSTR(kIOPMDestroyFVKeyOnStandbyKey), (avoid_keyStore ? kCFBooleanTrue : kCFBooleanFalse)); #endif exit: if(settings) CFRelease( settings ); return ret; } CFDictionaryRef IOPMCopySystemPowerSettings(void) { CFDictionaryRef systemPowerDictionary = NULL; CFDictionaryRef tmp_dict = NULL; SCPreferencesRef energyPrefs = NULL; energyPrefs = SCPreferencesCreate( kCFAllocatorDefault, kIOPMAppName, kIOPMPrefsPath ); if(!energyPrefs) { return NULL; } tmp_dict = isA_CFDictionary(SCPreferencesGetValue( energyPrefs, CFSTR("SystemPowerSettings"))); if(!tmp_dict) { goto exit; } systemPowerDictionary = CFDictionaryCreateCopy(0, tmp_dict); exit: if(energyPrefs) CFRelease(energyPrefs); return systemPowerDictionary; } IOReturn IOPMSetSystemPowerSetting( CFStringRef key, CFTypeRef value) { IOReturn ret = kIOReturnError; SCPreferencesRef energyPrefs = NULL; CFMutableDictionaryRef systemPowerDictionary = NULL; CFDictionaryRef tmp_dict = NULL; energyPrefs = SCPreferencesCreate( 0, kIOPMAppName, kIOPMPrefsPath ); if(!energyPrefs) { if(kSCStatusAccessError == SCError()) return kIOReturnNotPrivileged; else return kIOReturnError; } /* We lock energyPrefs here to prevent multiple simultaneous writes * modifying the same data. Must lock energyPrefs before reading * systemPowerSettings in IOPMCopySystemPowerSettings. */ if(!SCPreferencesLock(energyPrefs, true)) { if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged; else ret = kIOReturnError; goto exit; } tmp_dict = IOPMCopySystemPowerSettings(); if(tmp_dict) { systemPowerDictionary = CFDictionaryCreateMutableCopy(0, 0, tmp_dict); CFRelease(tmp_dict); tmp_dict = NULL; } else { systemPowerDictionary = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if(!systemPowerDictionary) { goto exit; } CFDictionarySetValue( systemPowerDictionary, key, value); ret = kIOReturnSuccess; if(!SCPreferencesSetValue( energyPrefs, CFSTR("SystemPowerSettings"), systemPowerDictionary)) { ret = kIOReturnError; goto exit; } if(!SCPreferencesCommitChanges(energyPrefs)) { // handle error if(kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged; else ret = kIOReturnError; goto exit; } ret = kIOReturnSuccess; exit: if(energyPrefs) { SCPreferencesUnlock(energyPrefs); CFRelease(energyPrefs); } return ret; } void IOPMOverrideDefaultPMPreferences(CFDictionaryRef overrideSettings) { SCDynamicStoreRef dynamic_store = NULL; if(0 == isA_CFDictionary(overrideSettings)) { return; } dynamic_store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("IOKit User Library - Override"), NULL, NULL); if(dynamic_store == NULL) return; // This is the simplest possible implementation of IOPMOverrideDefaultPMPreferences. // This assumes only one caller. If called multiple times, the last caller will // overwrite all previous callers values. SCDynamicStoreSetValue(dynamic_store, CFSTR(kIOPMDynamicStoreUserOverridesKey), overrideSettings); // And send a notification to anyone watching the preferences file. _doTouchEnergyPrefs(dynamic_store); CFRelease(dynamic_store); return; } /************************************************** * * Power Profiles * * **************************************************/ static void mergeDictIntoMutable( CFMutableDictionaryRef target, CFDictionaryRef overrides, bool overwrite) { const CFStringRef *keys; const CFTypeRef *objs; int count; int i; count = CFDictionaryGetCount(overrides); if(0 == count) return; keys = (CFStringRef *)malloc(sizeof(CFStringRef) * count); objs = (CFTypeRef *)malloc(sizeof(CFTypeRef) * count); if(!keys || !objs) return; CFDictionaryGetKeysAndValues(overrides, (const void **)keys, (const void **)objs); for(i=0; i= kIOPMNumPowerProfiles) return 0; // Battery value optional val = CFDictionaryGetValue(p, CFSTR(kIOPMBatteryPowerKey)); if(val) { CFNumberGetValue(val, kCFNumberIntType, &j); if(j<-1 || j>= kIOPMNumPowerProfiles) return 0; } // UPS value optional val = CFDictionaryGetValue(p, CFSTR(kIOPMUPSPowerKey)); if(val) { CFNumberGetValue(val, kCFNumberIntType, &j); if(j<-1 || j>= kIOPMNumPowerProfiles) return 0; } return 1; } static void _purgeUnsupportedPowerSources(CFMutableDictionaryRef p) { CFStringRef *ps_names = NULL; CFTypeRef ps_snap = NULL; int count; int i; ps_snap = IOPSCopyPowerSourcesInfo(); if(!ps_snap) return; count = CFDictionaryGetCount(p); ps_names = (CFStringRef *)malloc(count*sizeof(CFStringRef)); if(!ps_names) goto exit; CFDictionaryGetKeysAndValues(p, (CFTypeRef *)ps_names, NULL); for(i=0; icallback; if(!cb) return; // Execute callback (*cb)(c->context); } /******************************************************************************* **** **** readAllPMPlistSettings **** *******************************************************************************/ IOReturn readAllPMPlistSettings( bool removeUnsupportedSettings, CFMutableDictionaryRef *customSettings, CFDictionaryRef *profileSelections, bool *returnDefaultSettings) { /* * Read Custom Settings */ CFMutableDictionaryRef energyDict = NULL; CFDictionaryRef tmp_dict = NULL; SCPreferencesRef energyPrefs = NULL; CFMutableDictionaryRef batterySettings = NULL; CFMutableDictionaryRef ACSettings = NULL; CFMutableDictionaryRef UPSSettings = NULL; bool usingDefaults = true; bool prefsSuccess = false; /* * Read profiles */ CFDictionaryRef tmp = NULL; CFDictionaryRef defaultProfiles = NULL; CFStringRef *profileKeys = NULL; CFNumberRef *profileValues = NULL; bool activeProfilesSpecified = false; int profileCount; int i; bool profilesSuccess = false; CFMutableDictionaryRef acquiredProfiles = NULL; energyPrefs = SCPreferencesCreate( 0, kIOPMAppName, kIOPMPrefsPath ); if(!energyPrefs) { // Utter failure!!! if(customSettings) *customSettings = NULL; if(profileSelections) *profileSelections = NULL; return kIOReturnNotOpen; } /******************************************************************************* **** Read raw profiles com.apple.PowerManagement.plist *******************************************************************************/ tmp = SCPreferencesGetValue(energyPrefs, CFSTR("ActivePowerProfiles")); if(tmp && _isActiveProfileDictValid(tmp)) { acquiredProfiles = CFDictionaryCreateMutableCopy(0, 0, tmp); activeProfilesSpecified = true; } else { acquiredProfiles = NULL; } /******************************************************************************* **** Read custom settings dictionary from com.apple.PowerManagement.plist *******************************************************************************/ // Attempt to read battery & AC settings tmp_dict = isA_CFDictionary(SCPreferencesGetValue(energyPrefs, CFSTR("Custom Profile"))); // If com.apple.PowerManagement.xml opened correctly, read data from it if(tmp_dict) { usingDefaults = false; // Tiger preferences file format energyDict = CFDictionaryCreateMutableCopy( kCFAllocatorDefault, 0, tmp_dict); if(!energyDict) goto prefsExit; } else { // Try Panther/Jaguar prefs formats batterySettings = (CFMutableDictionaryRef)isA_CFDictionary( SCPreferencesGetValue(energyPrefs, CFSTR(kIOPMBatteryPowerKey))); ACSettings = (CFMutableDictionaryRef)isA_CFDictionary( SCPreferencesGetValue(energyPrefs, CFSTR(kIOPMACPowerKey))); UPSSettings = (CFMutableDictionaryRef)isA_CFDictionary( SCPreferencesGetValue(energyPrefs, CFSTR(kIOPMUPSPowerKey))); if ( batterySettings || ACSettings || UPSSettings ) usingDefaults = false; energyDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if(!energyDict) goto prefsExit; if(batterySettings) { CFDictionaryAddValue(energyDict, CFSTR(kIOPMBatteryPowerKey), batterySettings); } if(ACSettings) { CFDictionaryAddValue(energyDict, CFSTR(kIOPMACPowerKey), ACSettings); } if(UPSSettings) { CFDictionaryAddValue(energyDict, CFSTR(kIOPMUPSPowerKey), UPSSettings); } } // Make sure that the enclosed dictionaries are all mutable tmp = isA_CFDictionary(CFDictionaryGetValue( energyDict, CFSTR(kIOPMBatteryPowerKey))); if(tmp) { batterySettings = CFDictionaryCreateMutableCopy(0, 0, tmp); } else { batterySettings = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if(batterySettings) { CFDictionarySetValue(energyDict, CFSTR(kIOPMBatteryPowerKey), batterySettings); CFRelease(batterySettings); } else goto prefsExit; tmp = isA_CFDictionary(CFDictionaryGetValue( energyDict, CFSTR(kIOPMACPowerKey))); if(tmp) { ACSettings = CFDictionaryCreateMutableCopy(0, 0, tmp); } else { ACSettings = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if(ACSettings) { CFDictionarySetValue(energyDict, CFSTR(kIOPMACPowerKey), ACSettings); CFRelease(ACSettings); } else goto prefsExit; tmp = isA_CFDictionary(CFDictionaryGetValue( energyDict, CFSTR(kIOPMUPSPowerKey))); if(tmp) { UPSSettings = CFDictionaryCreateMutableCopy(0, 0, tmp); } else { UPSSettings = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if(UPSSettings) { CFDictionarySetValue(energyDict, CFSTR(kIOPMUPSPowerKey), UPSSettings); CFRelease(UPSSettings); } else goto prefsExit; // INVARIANT: At this point we want a mutable dictionary energyDict // containing 3 mutable preferences dictionaries that are either // empty or contain some settings. // Check for existence of Puma/Cheetah prefs format // And add settings defined there if present getCheetahPumaEnergySettings(energyDict); // Fill in any undefined settings from the system's provided defaults // IOPlatformExpert may specify different profile defaults, so we must // respect those when present. addSystemProfileEnergySettings(acquiredProfiles, energyDict); // Fill in any settings overriden by a user process. mergeUserDefaultOverriddenSettings(energyDict); // Fill in any undefined settings with our defaults // If no current or legacy prefs files exist, addDefaultEnergySettings() // completely populates the default EnergySaver preferences. addDefaultEnergySettings(energyDict); if (removeUnsupportedSettings) { // Remove any unsupported key/value pairs (including some of // those we just added in getDefaultEnergySettings) IOPMRemoveIrrelevantProperties(energyDict); } if(usingDefaults) { // If we couldn't find any user-specified settings on disk, // tag this dictionary as "Defaults" so that BatteryMonitor and // EnergySaver can tell whether these are user-selected // values or just the system defaults. CFDictionarySetValue(energyDict, CFSTR(kIOPMDefaultPreferencesKey), kCFBooleanTrue); } prefsSuccess = true; if( customSettings ) { *customSettings = energyDict; } prefsExit: if ( !prefsSuccess && customSettings) { *customSettings = NULL; } /******************************************************************************* **** Read custom profiles dictionary from com.apple.PowerManagement.plist ******************************************************************************/ if( !profileSelections ) { profilesSuccess = true; } else { // acquiredProfiles already contains the pre-read profiles data if(!acquiredProfiles) { acquiredProfiles = CFDictionaryCreateMutable(0, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if(!activeProfilesSpecified && !usingDefaults) { defaultProfiles = _createAllCustomProfileSelections(); } else { defaultProfiles = _createDefaultProfileSelections(); } // Merge default profiles into active profiles // If the user has any specified Profiles, we'll merge in the defaults // for any power sources that aren't specified. If there weren't any // profile choices, we'll just merge in (-1, -1, -1) for all custom or // (2, 1, 1) to the empty dictionary, as described in comments above. if(isA_CFDictionary(defaultProfiles)) { profileCount = CFDictionaryGetCount(defaultProfiles); profileKeys = malloc(sizeof(CFStringRef)*profileCount); profileValues = malloc(sizeof(CFNumberRef)*profileCount); if ( !profileKeys || !profileValues ) goto profilesExit; CFDictionaryGetKeysAndValues(defaultProfiles, (const void **)profileKeys, (const void **)profileValues); for(i=0; i