1/* 2 * Copyright (c) 2007 Apple Computer, Inc. All rights reserved. 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#include <CoreFoundation/CoreFoundation.h> 25 26#include <syslog.h> 27#include <unistd.h> 28#include <grp.h> 29#include <pwd.h> 30#include <mach/mach.h> 31#include <servers/bootstrap.h> 32#include <notify.h> 33#include <asl.h> 34#include <uuid/uuid.h> 35#include <pthread.h> 36#include <bsm/libbsm.h> 37#include <sys/sysctl.h> 38#include <xpc/private.h> 39#if !TARGET_OS_EMBEDDED 40#include <IOKit/platform/IOPlatformSupportPrivate.h> 41#include <AssertMacros.h> 42#endif 43#include <IOKit/pwr_mgt/IOPMLibPrivate.h> 44#include <IOKit/hid/IOHIDKeys.h> 45 46#include <Security/SecTask.h> 47 48#include "powermanagementServer.h" // mig generated 49 50#include "PMStore.h" 51#include "PMSettings.h" 52#include "UPSLowPower.h" 53#include "BatteryTimeRemaining.h" 54#include "AutoWakeScheduler.h" 55#include "RepeatingAutoWake.h" 56#include "PMAssertions.h" 57#include "PrivateLib.h" 58#include "TTYKeepAwake.h" 59#include "PMSystemEvents.h" 60#include "SystemLoad.h" 61#include "PMConnection.h" 62#include "ExternalMedia.h" 63#include "Platform.h" 64 65// To support importance donation across IPCs 66#include <libproc_internal.h> 67 68#define kIOPMAppName "Power Management configd plugin" 69#define kIOPMPrefsPath "com.apple.PowerManagement.xml" 70#define pwrLogDirName "/System/Library/PowerEvents" 71 72#ifndef kIOUPSDeviceKey 73// Also defined in ioupsd/IOUPSPrivate.h 74#define kIOUPSDeviceKey "UPSDevice" 75#define kIOPowerDeviceUsageKey 0x84 76#define kIOBatterySystemUsageKey 0x85 77#endif 78 79/* 80 * BSD notifications from loginwindow indicating shutdown 81 */ 82// kLWShutdownInitiated 83// User clicked shutdown: may be aborted later 84#define kLWShutdowntInitiated "com.apple.system.loginwindow.shutdownInitiated" 85 86// kLWRestartInitiated 87// User clicked restart: may be aborted later 88#define kLWRestartInitiated "com.apple.system.loginwindow.restartinitiated" 89 90// kLWLogoutCancelled 91// A previously initiated shutdown, restart, or logout, has been cancelled. 92#define kLWLogoutCancelled "com.apple.system.loginwindow.logoutcancelled" 93 94// kLWLogoutPointOfNoReturn 95// A previously initiated shutdown, restart, or logout has succeeded, and is 96// no longer abortable by anyone. Point of no return! 97#define kLWLogoutPointOfNoReturn "com.apple.system.loginwindow.logoutNoReturn" 98 99// kLWSULogoutInitiated 100// Loginwindow is beginning a sequence of 1. logout, 2. software update, 3. then restart. 101#define kLWSULogoutInitiated "com.apple.system.loginwindow.sulogoutinitiated" 102 103#define kDWTMsgHandlerDelay 10 // Time(in secs) for which DW Thermal msg handler is delayed 104 105#define LogObjectRetainCount(x, y) do {} while(0) 106/* #define LogObjectRetainCount(x, y) do { \ 107 asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: kernel retain = %d, user retain = %d\n", \ 108 x, IOObjectGetKernelRetainCount(y), IOObjectGetUserRetainCount(y)); } while(0) 109*/ 110 111// Global keys 112static CFStringRef gTZNotificationNameString = NULL; 113 114static SCPreferencesRef gESPreferences = NULL; 115 116static io_connect_t _pm_ack_port = 0; 117static io_iterator_t _ups_added_noteref = 0; 118static int _alreadyRunningIOUPSD = 0; 119 120static int gCPUPowerNotificationToken = 0; 121static bool gExpectingWakeFromSleepClockResync = false; 122static CFAbsoluteTime *gLastWakeTime = NULL; 123static CFTimeInterval *gLastSMCS3S0WakeInterval = NULL; 124static CFStringRef gCachedNextSleepWakeUUIDString = NULL; 125#if !TARGET_OS_EMBEDDED 126static int gLastWakeTimeToken = -1; 127static int gLastSMCS3S0WakeIntervalToken = -1; 128#endif 129 130typedef struct { 131 int shutdown; 132 int restart; 133 int cancel; 134 int pointofnoreturn; 135 int su; 136} LoginWindowNotifyTokens; 137static LoginWindowNotifyTokens lwNotify = {0,0,0,0,0}; 138 139static CFStringRef gConsoleNotifyKey = NULL; 140static bool gDisplayIsAsleep = false; 141static CFAbsoluteTime gSleepFromUserWakeTime = 0; 142static struct timeval gLastSleepTime = {0, 0}; 143 144static mach_port_t serverPort = MACH_PORT_NULL; 145__private_extern__ CFMachPortRef pmServerMachPort = NULL; 146#if !TARGET_OS_EMBEDDED 147static bool gSMCSupportsWakeupTimer = true; 148static int _darkWakeThermalEventCount = 0; 149static dispatch_source_t gDWTMsgDispatch; /* Darkwake thermal emergency message handler dispatch */ 150#endif 151 152#if TCPKEEPALIVE 153extern TCPKeepAliveStruct *gTCPKeepAlive; 154#endif 155 156// defined by MiG 157extern boolean_t powermanagement_server(mach_msg_header_t *, mach_msg_header_t *); 158 159 160// foward declarations 161static void initializeESPrefsDynamicStore(void); 162static void initializeInterestNotifications(void); 163static void initializeHIDInterestNotifications( 164 int usagePage, 165 IONotificationPortRef notify_port); 166static void initializeTimezoneChangeNotifications(void); 167static void initializeCalendarResyncNotification(void); 168static void initializeShutdownNotifications(void); 169static void initializeRootDomainInterestNotifications(void); 170#if !TARGET_OS_EMBEDDED 171static void initializeUserNotifications(void); 172static void enableSleepWakeWdog(); 173#endif 174static void initializeSleepWakeNotifications(void); 175 176static void SleepWakeCallback(void *,io_service_t, natural_t, void *); 177static void ESPrefsHaveChanged( 178 SCPreferencesRef prefs, 179 SCPreferencesNotification notificationType, 180 void *info); 181static void _ioupsd_exited(pid_t, int, struct rusage *, void *); 182static void UPSDeviceAdded(void *, io_iterator_t); 183static void ioregBatteryMatch(void *, io_iterator_t); 184static void ioregBatteryInterest(void *, io_service_t, natural_t, void *); 185static void RootDomainInterest(void *, io_service_t, natural_t, void *); 186static void broadcastGMTOffset(void); 187 188static void pushNewSleepWakeUUID(void); 189 190static void calendarRTCDidResync( 191 CFMachPortRef port, 192 void *msg, 193 CFIndex size, 194 void *info); 195 196static void lwShutdownCallback( 197 CFMachPortRef port, 198 void *msg, 199 CFIndex size, 200 void *info); 201 202static void timeZoneChangedCallBack( 203 CFNotificationCenterRef center, 204 void *observer, 205 CFStringRef notificationName, 206 const void *object, 207 CFDictionaryRef userInfo); 208 209static void displayMatched(void *, io_iterator_t); 210static void displayPowerStateChange( 211 void *ref, 212 io_service_t service, 213 natural_t messageType, 214 void *arg); 215 216static boolean_t pm_mig_demux( 217 mach_msg_header_t * request, 218 mach_msg_header_t * reply); 219 220static void mig_server_callback( 221 CFMachPortRef port, 222 void *msg, 223 CFIndex size, 224 void *info); 225 226static void incoming_XPC_connection(xpc_connection_t); 227static void xpc_register(void); 228 229static void AppClaimWakeReason(xpc_object_t claim); 230 231 232 233 234kern_return_t _io_pm_set_active_profile( 235 mach_port_t server, 236 audit_token_t token, 237 vm_offset_t profiles_ptr, 238 mach_msg_type_number_t profiles_len, 239 int *result); 240 241kern_return_t _io_pm_last_wake_time( 242 mach_port_t server, 243 vm_offset_t *out_wake_data, 244 mach_msg_type_number_t *out_wake_len, 245 vm_offset_t *out_delta_data, 246 mach_msg_type_number_t *out_delta_len, 247 int *return_val); 248 249 250 251static CFStringRef 252serverMPCopyDescription(const void *info) 253{ 254 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<IOKit Power Management MIG server>")); 255} 256 257// Callback is registered in PrivateLib.c 258__private_extern__ void dynamicStoreNotifyCallBack( 259 SCDynamicStoreRef store, 260 CFArrayRef changedKeys, 261 void *info); 262 263 264/* load 265 * 266 * configd entry point 267 */ 268 269 270 271 272int main(int argc __unused, char *argv[] __unused) 273{ 274 CFRunLoopSourceRef cfmp_rls = 0; 275 CFMachPortContext context = { 0, (void *)1, NULL, NULL, serverMPCopyDescription }; 276 kern_return_t kern_result = 0; 277 278 xpc_register(); 279 280 kern_result = bootstrap_check_in( 281 bootstrap_port, 282 kIOPMServerBootstrapName, 283 &serverPort); 284 285#if TARGET_OS_EMBEDDED 286 if (BOOTSTRAP_SUCCESS != kern_result) { 287 kern_result = mach_port_allocate( 288 mach_task_self(), 289 MACH_PORT_RIGHT_RECEIVE, 290 &serverPort); 291 292 if (KERN_SUCCESS == kern_result) { 293 kern_result = mach_port_insert_right( 294 mach_task_self(), 295 serverPort, serverPort, 296 MACH_MSG_TYPE_MAKE_SEND); 297 } 298 299 if (KERN_SUCCESS == kern_result) { 300 kern_result = bootstrap_register( 301 bootstrap_port, 302 kIOPMServerBootstrapName, 303 serverPort); 304 } 305 } 306#endif 307 308 if (BOOTSTRAP_SUCCESS != kern_result) { 309 syslog(LOG_ERR, "PM configd: bootstrap_register \"%s\" error = %d\n", 310 kIOPMServerBootstrapName, kern_result); 311 } 312 313 if (MACH_PORT_NULL != serverPort) 314 { 315 // Finish setting up mig handler callback on pmServerMachPort 316 pmServerMachPort = _SC_CFMachPortCreateWithPort( 317 "PowerManagement", 318 serverPort, 319 mig_server_callback, 320 &context); 321 } 322 if (pmServerMachPort) { 323 cfmp_rls = CFMachPortCreateRunLoopSource(0, pmServerMachPort, 0); 324 if (cfmp_rls) { 325 CFRunLoopAddSource(CFRunLoopGetCurrent(), cfmp_rls, kCFRunLoopDefaultMode); 326 CFRelease(cfmp_rls); 327 } 328 } 329 330 _getPMRunLoop(); 331 332 PMStoreLoad(); 333 334 initializeESPrefsDynamicStore(); 335 initializeInterestNotifications(); 336 initializeTimezoneChangeNotifications(); 337 initializeCalendarResyncNotification(); 338 initializeShutdownNotifications(); 339 initializeRootDomainInterestNotifications(); 340 341#if !TARGET_OS_EMBEDDED 342 initializeUserNotifications(); 343 _oneOffHacksSetup(); 344#endif 345 346 initializeSleepWakeNotifications(); 347 348 // Prime the messagetracer UUID pump 349 pushNewSleepWakeUUID(); 350 351 BatteryTimeRemaining_prime(); 352 PMSettings_prime(); 353 AutoWake_prime(); 354 PMAssertions_prime(); 355 PMSystemEvents_prime(); 356 SystemLoad_prime(); 357 PMConnection_prime(); 358 359#if !TARGET_OS_EMBEDDED 360 UPSLowPower_prime(); 361 TTYKeepAwake_prime(); 362 ExternalMedia_prime(); 363 364 createOnBootAssertions(); 365 enableSleepWakeWdog(); 366#endif 367 368 _unclamp_silent_running(false); 369 notify_post(kIOUserAssertionReSync); 370 logASLMessagePMStart(); 371 372 CFRunLoopRun(); 373 return 0; 374} 375 376 377 378 379static void ioregBatteryMatch( 380 void *refcon, 381 io_iterator_t b_iter) 382{ 383 IOPMBattery *tracking; 384 IONotificationPortRef notify = (IONotificationPortRef)refcon; 385 io_registry_entry_t battery; 386 io_object_t notification_ref; 387 388 while((battery = (io_registry_entry_t)IOIteratorNext(b_iter))) 389 { 390 // Add battery to our list of batteries 391 tracking = _newBatteryFound(battery); 392 393 LogObjectRetainCount("PM::BatteryMatch(M0) me", battery); 394 395 // And install an interest notification on it 396 IOServiceAddInterestNotification(notify, battery, 397 kIOGeneralInterest, ioregBatteryInterest, 398 (void *)tracking, ¬ification_ref); 399 400 LogObjectRetainCount("PM::BatteryMatch(M1) me", battery); 401 LogObjectRetainCount("PM::BatteryMatch(M1) msg_port", notification_ref); 402 403 tracking->msg_port = notification_ref; 404 IOObjectRelease(battery); 405 } 406 InternalEvaluateAssertions(); 407 InternalEvalConnections(); 408} 409 410 411static void ioregBatteryInterest( 412 void *refcon, 413 io_service_t batt, 414 natural_t messageType, 415 void *messageArgument) 416{ 417 IOPMBattery *changed_batt = (IOPMBattery *)refcon; 418 IOPMBattery **batt_stats; 419 420 if(kIOPMMessageBatteryStatusHasChanged == messageType) 421 { 422 // Update the arbiter 423 changed_batt->me = (io_registry_entry_t)batt; 424 _batteryChanged(changed_batt); 425 426 LogObjectRetainCount("PM:BatteryInterest(B0) msg_port", changed_batt->msg_port); 427 LogObjectRetainCount("PM:BatteryInterest(B1) msg_port", changed_batt->me); 428 429 batt_stats = _batteries(); 430 kernelPowerSourcesDidChange(changed_batt); 431 SystemLoadBatteriesHaveChanged(batt_stats); 432 InternalEvaluateAssertions(); 433 InternalEvalConnections(); 434 } 435 436 return; 437} 438 439 440__private_extern__ void 441ClockSleepWakeNotification(IOPMSystemPowerStateCapabilities old_cap, 442 IOPMSystemPowerStateCapabilities new_cap, 443 uint32_t changeFlags) 444{ 445 // Act on the notification before the dark wake to sleep transition 446 if (CAPABILITY_BIT_CHANGED(new_cap, old_cap, kIOPMSystemPowerStateCapabilityCPU) && 447 BIT_IS_SET(old_cap, kIOPMSystemPowerStateCapabilityCPU) && 448 BIT_IS_SET(changeFlags, kIOPMSystemCapabilityWillChange)) 449 { 450#if !TARGET_OS_EMBEDDED 451 // write SMC Key to re-enable SMC timer 452 _smcWakeTimerPrimer(); 453#endif 454 455 // Stash the last sleep time to ignore clock changes before 456 // this sleep is completed. 457 size_t len = sizeof(gLastSleepTime); 458 if (sysctlbyname("kern.sleeptime", &gLastSleepTime, &len, NULL, 0)) { 459 gLastSleepTime.tv_sec = 0; 460 gLastSleepTime.tv_usec = 0; 461 } 462 463 // The next clock resync occuring on wake from sleep shall be marked 464 // as the wake time. 465 gExpectingWakeFromSleepClockResync = true; 466 467#if !TARGET_OS_EMBEDDED 468 if (gLastWakeTimeToken >= 0) 469 notify_set_state(gLastWakeTimeToken, 0); 470 if (gLastSMCS3S0WakeIntervalToken >= 0) 471 notify_set_state(gLastSMCS3S0WakeIntervalToken, 0); 472#endif 473 // tell clients what our timezone offset is 474 broadcastGMTOffset(); 475 } 476} 477 478 479/* 480 * 481 * Receives notifications on system sleep and system wake. 482 * This callback is not called for maintenance sleep/wake. 483 */ 484static void 485SleepWakeCallback( 486 void *port, 487 io_service_t rootdomainservice, 488 natural_t messageType, 489 void *acknowledgementToken) 490{ 491 492 BatteryTimeRemainingSleepWakeNotification(messageType); 493 PMSettingsSleepWakeNotification(messageType); 494 495 // Log Message to MessageTracer 496 497 // Acknowledge message 498 switch ( messageType ) { 499 case kIOMessageSystemWillSleep: 500 if (isUserActiveRootDomain) { 501 gSleepFromUserWakeTime = CFAbsoluteTimeGetCurrent(); 502 userActiveHandleSleep(); 503 } 504 // Fall thru 505 case kIOMessageCanSystemSleep: 506 IOAllowPowerChange(_pm_ack_port, (long)acknowledgementToken); 507 break; 508 509 case kIOMessageSystemHasPoweredOn: 510 case kIOMessageSystemWillNotSleep: 511 _set_sleep_revert(true); 512 break; 513 514 default: 515 break; 516 } 517} 518 519/* ESPrefsHaveChanged 520 * 521 * Is the handler that configd calls when someone "applies" new Energy Saver 522 * Preferences. Since the preferences have probably changed, we re-read them 523 * from disk and transmit the new settings to the kernel. 524 */ 525static void 526ESPrefsHaveChanged( 527 SCPreferencesRef prefs, 528 SCPreferencesNotification notificationType, 529 void *info) 530{ 531 if ((kSCPreferencesNotificationCommit & notificationType) == 0) 532 return; 533 534 if (gESPreferences == prefs) 535 { 536 // Tell ES Prefs listeners that the prefs have changed 537 PMSettingsPrefsHaveChanged(); 538 mt2EvaluateSystemSupport(); 539#if !TARGET_OS_EMBEDDED 540 UPSLowPowerPrefsHaveChanged(); 541 TTYKeepAwakePrefsHaveChanged(); 542#endif 543 SystemLoadPrefsHaveChanged(); 544 } 545 546 return; 547} 548 549 550/* _ioupsd_exited 551 * 552 * Gets called (by configd) when /usr/libexec/ioupsd exits 553 */ 554static void _ioupsd_exited( 555 pid_t pid, 556 int status, 557 struct rusage *rusage, 558 void *context) 559{ 560 if(0 != status) 561 { 562 // ioupsd didn't exit cleanly. 563 syslog( 564 LOG_ERR, 565 "PowerManagement: /usr/libexec/ioupsd(%d) has exited with status %d\n", 566 pid, 567 status); 568 569 // relaunch 570 char *argv[2] = {"/usr/libexec/ioupsd", NULL}; 571 _SCDPluginExecCommand(&_ioupsd_exited, 0, 0, 0, 572 "/usr/libexec/ioupsd", argv); 573 } else { 574 _alreadyRunningIOUPSD = 0; 575 } 576} 577 578 579/* UPSDeviceAdded 580 * 581 * A UPS has been detected running on the system. 582 * 583 */ 584static void UPSDeviceAdded(void *refCon, io_iterator_t iterator) 585{ 586 io_object_t upsDevice = MACH_PORT_NULL; 587 588 while ( (upsDevice = IOIteratorNext(iterator)) ) 589 { 590 // If not running, launch the management process ioupsd now. 591 if(!_alreadyRunningIOUPSD) { 592 char *argv[2] = {"/usr/libexec/ioupsd", NULL}; 593 594 _alreadyRunningIOUPSD = 1; 595 _SCDPluginExecCommand(&_ioupsd_exited, 0, 0, 0, 596 "/usr/libexec/ioupsd", argv); 597 } 598 IOObjectRelease(upsDevice); 599 } 600} 601 602 603/* timeZoneChangedCallback 604 * 605 * When our timezone offset changes, tell interested drivers. 606 */ 607static void 608timeZoneChangedCallBack( 609 CFNotificationCenterRef center, 610 void *observer, 611 CFStringRef notificationName, 612 const void *object, 613 CFDictionaryRef userInfo) 614{ 615 if( CFEqual(notificationName, gTZNotificationNameString) ) 616 { 617 broadcastGMTOffset(); 618 } 619} 620 621 622/* broadcastGMTOffset 623 * 624 * Tell the timezone clients what the seconds offset from GMT is. This info 625 * is delivered via the kernel PMSettings interface. 626 * 627 * Notifications are sent: 628 * - at boot time 629 * - when timezone changes 630 * - at sleep time* 631 * - at display sleep time* 632 * 633 * * PM configd does not receive a notification when daylight savings time 634 * changes. In case the system has entered daylight savings time since 635 * boot, we re-broadcast the tz offset at sleep and display sleep. 636 */ 637static void 638broadcastGMTOffset(void) 639{ 640 CFTimeZoneRef tzr = NULL; 641 CFNumberRef n = NULL; 642 int secondsOffset = 0; 643 644 CFTimeZoneResetSystem(); 645 tzr = CFTimeZoneCopySystem(); 646 if(!tzr) return; 647 648 secondsOffset = (int)CFTimeZoneGetSecondsFromGMT(tzr, CFAbsoluteTimeGetCurrent()); 649 n = CFNumberCreate(0, kCFNumberIntType, &secondsOffset); 650 if(!n) { 651 goto exit; 652 } 653 654 // Tell the root domain what our timezone's offset from GMT is. 655 // IOPMrootdomain will relay the message on to interested PMSetting clients. 656 _setRootDomainProperty(CFSTR("TimeZoneOffsetSeconds"), n); 657 658exit: 659 if(tzr) CFRelease(tzr); 660 if(n) CFRelease(n); 661 return; 662} 663 664/* lwShutdownCallback 665 * 666 * 667 * 668 * loginwindow shutdown handler 669 * 670 */ 671static void lwShutdownCallback( 672 CFMachPortRef port, 673 void *msg, 674 CFIndex size, 675 void *info) 676{ 677 mach_msg_header_t *header = (mach_msg_header_t *)msg; 678 CFNumberRef n = NULL; 679 static bool amidst_shutdown = false; 680 static int consoleShutdownState = kIOPMStateConsoleShutdownNone; 681 static int lastConsoleShutdownState = 0; 682 683 if (header->msgh_id == gCPUPowerNotificationToken) 684 { 685 // System CPU power status has changed 686 SystemLoadCPUPowerHasChanged(NULL); 687 } else if (header->msgh_id == lwNotify.su) 688 { 689 // Loginwindow is logging out to begin a several-minute 690 // software update. We'll suppress the immediately next shoutdown 691 // and logout messages. 692 consoleShutdownState = kIOPMStateConsoleSULogoutInitiated; 693 694 } else if (header->msgh_id == lwNotify.shutdown) 695 { 696 // Loginwindow put a shutdown confirm panel up on screen 697 // The user has not necessarily even clicked on it yet 698 amidst_shutdown = true; 699 consoleShutdownState = kIOPMStateConsoleShutdownPossible; 700 701 } else if (header->msgh_id == lwNotify.restart) 702 { 703 // Loginwindow put a restart confirm panel up on screen 704 // The user has not necessarily even clicked on it yet 705 amidst_shutdown = true; 706 consoleShutdownState = kIOPMStateConsoleShutdownPossible; 707 708 } else if (header->msgh_id == lwNotify.cancel) 709 { 710 amidst_shutdown = false; 711 consoleShutdownState = kIOPMStateConsoleShutdownNone; 712 713 } else if (amidst_shutdown 714 && (header->msgh_id == lwNotify.pointofnoreturn)) 715 { 716 // Whatever shutdown or restart that was in progress has succeeded. 717 // All apps are quit, there's no more user input required. We will 718 // hereby disable sleep for the remainder of time spent shutting down 719 // this machine. 720 721 _setRootDomainProperty(CFSTR("System Shutdown"), kCFBooleanTrue); 722 consoleShutdownState = kIOPMStateConsoleShutdownCertain; 723 } 724 725 // Tell interested kernel drivers where we are in the GUI shutdown. 726 if (lastConsoleShutdownState != consoleShutdownState) { 727 728 n = CFNumberCreate(0, kCFNumberIntType, &consoleShutdownState); 729 if (n) { 730 _setRootDomainProperty( CFSTR(kIOPMStateConsoleShutdown), n) ; 731 CFRelease(n); 732 } 733 734 lastConsoleShutdownState = consoleShutdownState; 735 } 736 737 738 return; 739} 740 741 742/* displayPowerStateChange 743 * 744 * displayPowerStateChange gets notified when the display changes power state. 745 * Power state changes look like this: 746 * (1) Full power -> dim 747 * (2) dim -> display sleep 748 * (3) display sleep -> display sleep 749 * 750 * We're interested in state transition 2. On transition to state 2 we 751 * broadcast the system clock's offset from GMT. 752 */ 753static void 754displayPowerStateChange(void *ref, io_service_t service, natural_t messageType, void *arg) 755{ 756 IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification*) arg; 757 bool prevState = gDisplayIsAsleep; 758 759 switch (messageType) 760 { 761 // Display Wrangler power stateNumber values 762 // 4 Display ON 763 // 3 Display Dim 764 // 2 Display Sleep 765 // 1 Not visible to user 766 // 0 Not visible to user 767 768 case kIOMessageDeviceWillPowerOff: 769 if ( params->stateNumber != 4 ) 770 { 771 gDisplayIsAsleep = true; 772 } 773 774 if ( params->stateNumber <= 1) 775 { 776 // Notify a SystemLoad state change when display is completely off 777 SystemLoadDisplayPowerStateHasChanged(gDisplayIsAsleep); 778 // Display is transition from dim to full sleep. 779 broadcastGMTOffset(); 780 } 781 break; 782 783 case kIOMessageDeviceHasPoweredOn: 784 if ( params->stateNumber == 4 ) 785 { 786 gDisplayIsAsleep = false; 787 SystemLoadDisplayPowerStateHasChanged(gDisplayIsAsleep); 788 } 789 790 break; 791 } 792 793 if (prevState != gDisplayIsAsleep) { 794 logASLDisplayStateChange(); 795 } 796} 797 798__private_extern__ bool isDisplayAsleep( ) 799{ 800 return gDisplayIsAsleep; 801} 802 803/* initializeESPrefsDynamicStore 804 * 805 * Registers a handler that configd calls when someone changes com.apple.PowerManagement.xml 806 */ 807static void 808initializeESPrefsDynamicStore(void) 809{ 810 gESPreferences = SCPreferencesCreate( 811 kCFAllocatorDefault, 812 CFSTR("com.apple.configd.powermanagement"), 813 CFSTR(kIOPMPrefsPath)); 814 815 if (gESPreferences) 816 { 817 SCPreferencesSetCallback( 818 gESPreferences, 819 (SCPreferencesCallBack)ESPrefsHaveChanged, 820 (SCPreferencesContext *)NULL); 821 822 SCPreferencesScheduleWithRunLoop( 823 gESPreferences, 824 CFRunLoopGetCurrent(), 825 kCFRunLoopDefaultMode); 826 } 827 828 return; 829} 830 831 832/* pushNewSleepWakeUUID 833 * 834 * Called (1) At boot, and (2) When kernel PM uses its current UUID. 835 * We pre-allocate the UUID here and send it to the kernel, but the kernel 836 * will not activate it until the _next_ sleep/wake session begins. 837 * 838 * Global gCachedNextSleepWakeUUIDString will always reflect the next 839 * upcoming sleep/wake session UUID; not the current UUID. 840 */ 841static void pushNewSleepWakeUUID(void) 842{ 843 uuid_t new_uuid; 844 uuid_string_t new_uuid_string; 845 846 io_registry_entry_t root_domain = getRootDomain(); 847 848 if (IO_OBJECT_NULL == root_domain) { 849 return; 850 } 851 852 uuid_generate(new_uuid); 853 uuid_unparse_upper(new_uuid, new_uuid_string); 854 855 if (gCachedNextSleepWakeUUIDString) 856 { 857 CFRelease(gCachedNextSleepWakeUUIDString); 858 859 gCachedNextSleepWakeUUIDString = NULL; 860 } 861 862 if ((gCachedNextSleepWakeUUIDString = CFStringCreateWithCString(0, new_uuid_string, kCFStringEncodingUTF8))) 863 { 864 IORegistryEntrySetCFProperty(root_domain, CFSTR(kIOPMSleepWakeUUIDKey), gCachedNextSleepWakeUUIDString); 865 } 866 return; 867} 868 869 870static void AppClaimWakeReason(xpc_object_t claim) 871{ 872 const char *id; 873 const char *reason; 874 xpc_object_t d; 875 876 if (!claim) { 877 return; 878 } 879 880 id = xpc_dictionary_get_string(claim, "identity"), 881 reason = xpc_dictionary_get_string(claim, "reason"), 882 d = xpc_dictionary_get_value(claim, "description"); 883 884 logASLAppWakeReason(id, reason); 885} 886 887static void incoming_XPC_connection(xpc_connection_t peer) 888{ 889 xpc_connection_set_event_handler(peer, 890 ^(xpc_object_t event) { 891 SecTaskRef secTask = NULL; 892 CFTypeRef entitled_DarkWakeControl = NULL; 893 audit_token_t token; 894 895 xpc_connection_get_audit_token(peer, &token); 896 897 secTask = SecTaskCreateWithAuditToken(kCFAllocatorDefault, token); 898 if (secTask) { 899 entitled_DarkWakeControl = SecTaskCopyValueForEntitlement(secTask, kIOPMDarkWakeControlEntitlement, NULL); 900 } 901 902 if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) { 903 904 xpc_object_t inEvent; 905 906 if (entitled_DarkWakeControl 907 && (inEvent = xpc_dictionary_get_value(event, "claimSystemWakeEvent"))) 908 { 909 AppClaimWakeReason(inEvent); 910 } 911 } 912 913 if (secTask) { 914 CFRelease(secTask); 915 } 916 if (entitled_DarkWakeControl) { 917 CFRelease(entitled_DarkWakeControl); 918 } 919 }); 920 921 xpc_connection_resume(peer); 922 return; 923} 924 925static void xpc_register(void) 926{ 927 xpc_connection_t connection; 928 929 connection = xpc_connection_create_mach_service( 930 "com.apple.iokit.powerdxpc", 931 dispatch_get_main_queue(), 932 XPC_CONNECTION_MACH_SERVICE_LISTENER); 933 934 xpc_connection_set_target_queue(connection, dispatch_get_main_queue()); 935 936 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) { 937 xpc_type_t type = xpc_get_type(event); 938 if (type == XPC_TYPE_CONNECTION) { 939 incoming_XPC_connection((xpc_connection_t)event); 940 } 941 }); 942 943 xpc_connection_resume(connection); 944} 945 946 947static boolean_t 948pm_mig_demux( 949 mach_msg_header_t * request, 950 mach_msg_header_t * reply) 951{ 952 mach_dead_name_notification_t *deadRequest = 953 (mach_dead_name_notification_t *)request; 954 boolean_t processed = FALSE; 955 956 processed = powermanagement_server(request, reply); 957 958 if (processed) 959 return true; 960 961 if (MACH_NOTIFY_DEAD_NAME == request->msgh_id) 962 { 963 __MACH_PORT_DEBUG(true, "pm_mig_demux: Dead name port should have 1+ send right(s)", deadRequest->not_port); 964 965 PMConnectionHandleDeadName(deadRequest->not_port); 966 967 __MACH_PORT_DEBUG(true, "pm_mig_demux: Deallocating dead name port", deadRequest->not_port); 968 mach_port_deallocate(mach_task_self(), deadRequest->not_port); 969 970 reply->msgh_bits = 0; 971 reply->msgh_remote_port = MACH_PORT_NULL; 972 973 return TRUE; 974 } 975 976 // mig request is not in our subsystem range! 977 // generate error reply packet 978 reply->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request->msgh_bits), 0); 979 reply->msgh_remote_port = request->msgh_remote_port; 980 reply->msgh_size = sizeof(mig_reply_error_t); /* Minimal size */ 981 reply->msgh_local_port = MACH_PORT_NULL; 982 reply->msgh_id = request->msgh_id + 100; 983 ((mig_reply_error_t *)reply)->NDR = NDR_record; 984 ((mig_reply_error_t *)reply)->RetCode = MIG_BAD_ID; 985 986 return processed; 987} 988 989 990 991static void 992mig_server_callback(CFMachPortRef port, void *msg, CFIndex size, void *info) 993{ 994 mig_reply_error_t * bufRequest = msg; 995 mig_reply_error_t * bufReply = CFAllocatorAllocate( 996 NULL, _powermanagement_subsystem.maxsize, 0); 997 mach_msg_return_t mr; 998 int options; 999 1000 __MACH_PORT_DEBUG(true, "mig_server_callback", serverPort); 1001 1002 /* we have a request message */ 1003 (void) pm_mig_demux(&bufRequest->Head, &bufReply->Head); 1004 1005 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && 1006 (bufReply->RetCode != KERN_SUCCESS)) { 1007 1008 if (bufReply->RetCode == MIG_NO_REPLY) { 1009 /* 1010 * This return code is a little tricky -- it appears that the 1011 * demux routine found an error of some sort, but since that 1012 * error would not normally get returned either to the local 1013 * user or the remote one, we pretend it's ok. 1014 */ 1015 goto out; 1016 1017 } 1018 1019 /* 1020 * destroy any out-of-line data in the request buffer but don't destroy 1021 * the reply port right (since we need that to send an error message). 1022 */ 1023 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL; 1024 mach_msg_destroy(&bufRequest->Head); 1025 } 1026 1027 if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) { 1028 /* no reply port, so destroy the reply */ 1029 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 1030 mach_msg_destroy(&bufReply->Head); 1031 } 1032 goto out; 1033 } 1034 1035 /* 1036 * send reply. 1037 * 1038 * We don't want to block indefinitely because the client 1039 * isn't receiving messages from the reply port. 1040 * If we have a send-once right for the reply port, then 1041 * this isn't a concern because the send won't block. 1042 * If we have a send right, we need to use MACH_SEND_TIMEOUT. 1043 * To avoid falling off the kernel's fast RPC path unnecessarily, 1044 * we only supply MACH_SEND_TIMEOUT when absolutely necessary. 1045 */ 1046 1047 options = MACH_SEND_MSG; 1048 if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE) { 1049 options |= MACH_SEND_TIMEOUT; 1050 } 1051 mr = mach_msg(&bufReply->Head, /* msg */ 1052 options, /* option */ 1053 bufReply->Head.msgh_size, /* send_size */ 1054 0, /* rcv_size */ 1055 MACH_PORT_NULL, /* rcv_name */ 1056 MACH_MSG_TIMEOUT_NONE, /* timeout */ 1057 MACH_PORT_NULL); /* notify */ 1058 1059 1060 /* Has a message error occurred? */ 1061 switch (mr) { 1062 case MACH_SEND_INVALID_DEST: 1063 case MACH_SEND_TIMED_OUT: 1064 /* the reply can't be delivered, so destroy it */ 1065 mach_msg_destroy(&bufReply->Head); 1066 break; 1067 1068 default : 1069 /* Includes success case. */ 1070 break; 1071 } 1072 1073 1074out: 1075 CFAllocatorDeallocate(NULL, bufReply); 1076 return; 1077 1078} 1079 1080/* dynamicStoreNotifyCallBack 1081 * 1082 * Changed Keys in dynamic store 1083 * 1084 */ 1085__private_extern__ 1086void dynamicStoreNotifyCallBack( 1087 SCDynamicStoreRef store, 1088 CFArrayRef changedKeys, 1089 void *info) 1090{ 1091 CFRange range = CFRangeMake(0, 1092 CFArrayGetCount(changedKeys)); 1093 1094 // Check for Console user change 1095 if (gConsoleNotifyKey 1096 && CFArrayContainsValue(changedKeys, 1097 range, 1098 gConsoleNotifyKey)) 1099 { 1100#if !TARGET_OS_EMBEDDED 1101 SystemLoadUserStateHasChanged(); 1102#endif 1103 } 1104 1105 return; 1106} 1107 1108kern_return_t _io_pm_set_value_int( 1109 mach_port_t server, 1110 audit_token_t token, 1111 int selector, 1112 int inValue, 1113 int *result) 1114{ 1115 uid_t callerUID; 1116 audit_token_to_au32(token, NULL, NULL, NULL, &callerUID, 0, 0, NULL, NULL); 1117 1118 *result = kIOReturnSuccess; 1119 switch (selector) { 1120 case kIOPMSetNoPoll: 1121 BatterySetNoPoll(inValue ? true:false); 1122 break; 1123 1124 case kIOPMSetAssertionActivityLog: 1125 setAssertionActivityLog(inValue); 1126 break; 1127 1128 case kIOPMSetAssertionActivityAggregate: 1129 setAssertionActivityAggregate(inValue); 1130 break; 1131 1132 case kIOPMSetReservePowerMode: 1133 if (!auditTokenHasEntitlement(token, kIOPMReservePwrCtrlEntitlement)) 1134 *result = kIOReturnNotPrivileged; 1135 else 1136 *result = setReservePwrMode(inValue); 1137 1138 default: 1139 break; 1140 } 1141 return KERN_SUCCESS; 1142} 1143 1144 1145kern_return_t _io_pm_get_value_int( 1146 mach_port_t server, 1147 audit_token_t token, 1148 int selector, 1149 int *outValue) 1150{ 1151 uid_t callerUID; 1152 audit_token_to_au32(token, NULL, NULL, NULL, &callerUID, 0, 0, NULL, NULL); 1153 1154 *outValue = 0; 1155 1156 switch(selector) 1157 { 1158#if !TARGET_OS_EMBEDDED 1159 case kIOPMGetSilentRunningInfo: 1160 if ( smcSilentRunningSupport( )) 1161 *outValue = 1; 1162 else 1163 *outValue = 0; 1164 break; 1165 1166 case kIOPMMT2Bookmark: 1167 if (0 == callerUID) 1168 { 1169 mt2PublishReports(); 1170 *outValue = 0; 1171 } else { 1172 *outValue = 1; 1173 } 1174 break; 1175 case kIOPMDarkWakeThermalEventCount: 1176 *outValue = _darkWakeThermalEventCount; 1177 break; 1178#if TCPKEEPALIVE 1179 case kIOPMTCPKeepAliveExpirationOverride: 1180 if (gTCPKeepAlive) { 1181 *outValue = gTCPKeepAlive->overrideSec; 1182 } 1183 break; 1184 1185 case kIOPMTCPKeepAliveIsActive: 1186 if (gTCPKeepAlive) { 1187 *outValue = (getTCPKeepAliveState(NULL, 0) == kActive) ? true : false; 1188 } 1189 break; 1190#endif 1191 1192#endif 1193 default: 1194 *outValue = 0; 1195 break; 1196 1197 } 1198 return KERN_SUCCESS; 1199} 1200 1201 1202 1203kern_return_t _io_pm_force_active_settings( 1204 mach_port_t server, 1205 audit_token_t token, 1206 vm_offset_t settings_ptr, 1207 mach_msg_type_number_t settings_len, 1208 int *result) 1209{ 1210 void *settings_buf = (void *)settings_ptr; 1211 CFDictionaryRef force_settings = NULL; 1212 uid_t callerUID; 1213 1214 audit_token_to_au32(token, NULL, &callerUID, NULL, NULL, NULL, NULL, NULL, NULL); 1215 1216 if (0 != callerUID) { 1217 // Caller must be root 1218 *result = kIOReturnNotPrivileged; 1219 } else { 1220 force_settings = (CFDictionaryRef)IOCFUnserialize(settings_buf, 0, 0, 0); 1221 1222 if(isA_CFDictionary(force_settings)) 1223 { 1224 *result = _activateForcedSettings(force_settings); 1225 } else { 1226 *result = kIOReturnBadArgument; 1227 } 1228 1229 if(force_settings) 1230 { 1231 CFRelease(force_settings); 1232 } 1233 } 1234 1235 // deallocate client's memory 1236 vm_deallocate(mach_task_self(), (vm_address_t)settings_ptr, settings_len); 1237 1238 return KERN_SUCCESS; 1239} 1240 1241kern_return_t _io_pm_set_active_profile( 1242 mach_port_t server, 1243 audit_token_t token, 1244 vm_offset_t profiles_ptr, 1245 mach_msg_type_number_t profiles_len, 1246 int *result) 1247{ 1248 void *profiles_buf = (void *)profiles_ptr; 1249 CFDictionaryRef power_profiles = NULL; 1250 uid_t callerUID; 1251 gid_t callerGID; 1252 1253 audit_token_to_au32(token, NULL, &callerUID, &callerGID, NULL, NULL, NULL, NULL, NULL); 1254 1255 power_profiles = (CFDictionaryRef)IOCFUnserialize(profiles_buf, 0, 0, 0); 1256 if(isA_CFDictionary(power_profiles)) { 1257 *result = _IOPMSetActivePowerProfilesRequiresRoot(power_profiles, callerUID, callerGID); 1258 CFRelease(power_profiles); 1259 } else if(power_profiles) { 1260 CFRelease(power_profiles); 1261 } 1262 1263 // deallocate client's memory 1264 vm_deallocate(mach_task_self(), (vm_address_t)profiles_ptr, profiles_len); 1265 1266 return KERN_SUCCESS; 1267} 1268 1269 1270 1271 1272/* initializeInteresteNotifications 1273 * 1274 * Sets up the notification of general interest from the RootDomain 1275 */ 1276static void 1277initializeInterestNotifications() 1278{ 1279 IONotificationPortRef notify_port = 0; 1280 io_iterator_t battery_iter = 0; 1281 io_iterator_t display_iter = 0; 1282 CFRunLoopSourceRef rlser = 0; 1283 1284 kern_return_t kr; 1285 1286 /* Notifier */ 1287 notify_port = IONotificationPortCreate(0); 1288 rlser = IONotificationPortGetRunLoopSource(notify_port); 1289 if(!rlser) return; 1290 CFRunLoopAddSource(CFRunLoopGetCurrent(), rlser, kCFRunLoopDefaultMode); 1291 1292 1293 kr = IOServiceAddMatchingNotification( 1294 notify_port, 1295 kIOFirstMatchNotification, 1296 IOServiceMatching("IOPMPowerSource"), 1297 ioregBatteryMatch, 1298 (void *)notify_port, 1299 &battery_iter); 1300 if(KERN_SUCCESS == kr) 1301 { 1302 // Install notifications on existing instances. 1303 ioregBatteryMatch((void *)notify_port, battery_iter); 1304 } 1305 1306 kr = IOServiceAddMatchingNotification( 1307 notify_port, 1308 kIOFirstMatchNotification, 1309 IOServiceMatching("IODisplayWrangler"), 1310 displayMatched, 1311 (void *)notify_port, 1312 &display_iter); 1313 if(KERN_SUCCESS == kr) 1314 { 1315 // Install notifications on existing instances. 1316 displayMatched((void *)notify_port, display_iter); 1317 } 1318 else { 1319 asl_log(NULL, NULL, ASL_LEVEL_ERR, 1320 "Failed to match DisplayWrangler(0x%x)\n", kr); 1321 } 1322 1323 // Listen for Power devices and Battery Systems to start ioupsd 1324 initializeHIDInterestNotifications(kIOPowerDeviceUsageKey, notify_port); 1325 initializeHIDInterestNotifications(kIOBatterySystemUsageKey, notify_port); 1326} 1327 1328static void 1329initializeHIDInterestNotifications(int usagePage, 1330 IONotificationPortRef notify_port) 1331{ 1332 CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOHIDDeviceKey); 1333 if (!matchingDict) { 1334 return; 1335 } 1336 1337 // We need to box the Usage Page value up into a CFNumber... sorry bout that 1338 CFNumberRef cfUsagePageKey = CFNumberCreate(kCFAllocatorDefault, 1339 kCFNumberIntType, 1340 &usagePage); 1341 if (!cfUsagePageKey) { 1342 CFRelease(matchingDict); 1343 return; 1344 } 1345 1346 CFDictionarySetValue(matchingDict, 1347 CFSTR(kIOHIDPrimaryUsagePageKey), 1348 cfUsagePageKey); 1349 CFRelease(cfUsagePageKey); 1350 1351 1352 // Now set up a notification to be called when a device is first matched by 1353 // I/O Kit. Note that this will not catch any devices that were already 1354 // plugged in so we take care of those later. 1355 kern_return_t kr = 1356 IOServiceAddMatchingNotification(notify_port, 1357 kIOFirstMatchNotification, 1358 matchingDict, 1359 UPSDeviceAdded, 1360 NULL, 1361 &_ups_added_noteref); 1362 1363 matchingDict = 0; // reference consumed by AddMatchingNotification 1364 if ( kr == kIOReturnSuccess ) { 1365 // Check for existing matching devices and launch ioupsd if present. 1366 UPSDeviceAdded( NULL, _ups_added_noteref); 1367 } 1368} 1369 1370/* initializeTimezoneChangeNotifications 1371 * 1372 * Sets up the tz notifications that we re-broadcast to all interested 1373 * kernel clients listening via PMSettings 1374 */ 1375static void 1376initializeTimezoneChangeNotifications(void) 1377{ 1378 CFNotificationCenterRef distNoteCenter = NULL; 1379 1380 gTZNotificationNameString = CFStringCreateWithCString( 1381 kCFAllocatorDefault, 1382 "NSSystemTimeZoneDidChangeDistributedNotification", 1383 kCFStringEncodingMacRoman); 1384 1385#if TARGET_OS_EMBEDDED 1386 distNoteCenter = CFNotificationCenterGetDarwinNotifyCenter(); 1387#else 1388 distNoteCenter = CFNotificationCenterGetDistributedCenter(); 1389#endif 1390 if(distNoteCenter) 1391 { 1392 CFNotificationCenterAddObserver( 1393 distNoteCenter, 1394 NULL, 1395 timeZoneChangedCallBack, 1396 gTZNotificationNameString, 1397 NULL, 1398 CFNotificationSuspensionBehaviorDeliverImmediately); 1399 } 1400 1401 // Boot time - tell clients what our timezone offset is 1402 broadcastGMTOffset(); 1403} 1404 1405static void initializeCalendarResyncNotification(void) 1406{ 1407 CFMachPortRef mpref = NULL; 1408 CFRunLoopSourceRef mpsrc = NULL; 1409 mach_port_t nport, tport; 1410 kern_return_t result; 1411 1412 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &nport); 1413 if (result != KERN_SUCCESS) { 1414 goto exit; 1415 } 1416 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &tport); 1417 if (result != KERN_SUCCESS) { 1418 goto exit; 1419 } 1420 result = mach_port_move_member(mach_task_self(), tport, nport); 1421 if (result != KERN_SUCCESS) { 1422 goto exit; 1423 } 1424 result = host_request_notification(mach_host_self(), HOST_NOTIFY_CALENDAR_CHANGE, tport); 1425 if (result != KERN_SUCCESS) { 1426 goto exit; 1427 } 1428 1429 mpref = _SC_CFMachPortCreateWithPort("PowerManagement/calendarResync", tport, calendarRTCDidResync, NULL); 1430 if (mpref) { 1431 mpsrc = CFMachPortCreateRunLoopSource(0, mpref, 0); 1432 if (mpsrc) { 1433 CFRunLoopAddSource(CFRunLoopGetCurrent(), mpsrc, kCFRunLoopDefaultMode); 1434 CFRelease(mpsrc); 1435 } 1436 CFRelease(mpref); 1437 } 1438 1439exit: 1440 return; 1441} 1442 1443static void calendarRTCDidResync_getSMCWakeInterval(void) 1444{ 1445#if !TARGET_OS_EMBEDDED 1446 uint16_t wakeup_smc_result = 0; 1447 IOReturn ret = kIOReturnSuccess; 1448#endif 1449 CFAbsoluteTime lastWakeTime; 1450 struct timeval lastSleepTime; 1451 size_t len = sizeof(struct timeval); 1452 1453 // Capture this as early as possible 1454 lastWakeTime = CFAbsoluteTimeGetCurrent(); 1455 1456 if (!gExpectingWakeFromSleepClockResync) { 1457 // This is a non-wake-from-sleep clock resync, so we'll ignore it. 1458 goto exit; 1459 } 1460 1461 if (sysctlbyname("kern.sleeptime", &lastSleepTime, &len, NULL, 0) || 1462 ((gLastSleepTime.tv_sec == lastSleepTime.tv_sec) && 1463 (gLastSleepTime.tv_usec == lastSleepTime.tv_usec))) 1464 { 1465 // This is a clock resync after sleep has started but before 1466 // platform sleep. 1467 goto exit; 1468 } 1469 1470 // if needed, init standalone memory for last wake time data 1471 if (!gLastSMCS3S0WakeInterval) { 1472 size_t bufSize; 1473 1474 bufSize = sizeof(*gLastWakeTime) + sizeof(*gLastSMCS3S0WakeInterval); 1475 if (0 != vm_allocate(mach_task_self(), (void*)&gLastWakeTime, 1476 bufSize, VM_FLAGS_ANYWHERE)) { 1477 return; 1478 } 1479 gLastSMCS3S0WakeInterval = gLastWakeTime + 1; 1480 } else { 1481 // validate pointers allocated earlier 1482 if (!gLastWakeTime || !gLastSMCS3S0WakeInterval) 1483 return; 1484 } 1485 1486 // This is a wake-from-sleep resync, so commit the last wake time 1487 *gLastWakeTime = lastWakeTime; 1488 *gLastSMCS3S0WakeInterval = 0; 1489 gExpectingWakeFromSleepClockResync = false; 1490 1491 // Re-enable battery time remaining calculations 1492 (void) BatteryTimeRemainingRTCDidResync(); 1493 1494#if !TARGET_OS_EMBEDDED 1495 if (!gSMCSupportsWakeupTimer) { 1496 // This system's SMC doesn't support a wakeup time, so we're done 1497 goto exit; 1498 } 1499 1500 if (gLastWakeTimeToken < 0) 1501 notify_register_check(kIOPMLastWakeTimeString, &gLastWakeTimeToken); 1502 if (gLastSMCS3S0WakeIntervalToken < 0) 1503 notify_register_check(kIOPMLastWakeTimeSMCDataString, &gLastSMCS3S0WakeIntervalToken); 1504 1505 // Read SMC key for precise timing between when the wake event physically occurred 1506 // and now (i.e. the moment we read the key). 1507 // - SMC key returns the delta in tens of milliseconds 1508 ret = _smcWakeTimerGetResults(&wakeup_smc_result); 1509 if ((ret != kIOReturnSuccess) || (wakeup_smc_result == 0)) 1510 { 1511 if (kIOReturnNotFound == ret) { 1512 gSMCSupportsWakeupTimer = false; 1513 } 1514 goto exit; 1515 } 1516 // re-sample the current time closer to the SMC key read 1517 *gLastWakeTime = CFAbsoluteTimeGetCurrent(); 1518 1519 // convert 10x msecs to (double)seconds 1520 *gLastSMCS3S0WakeInterval = ((double)wakeup_smc_result / 100.0); 1521 1522 // And we adjust backwards to determine the real time of physical wake. 1523 *gLastWakeTime -= *gLastSMCS3S0WakeInterval; 1524 1525 if (gLastWakeTimeToken >= 0) { 1526 union { 1527 uint64_t u64; 1528 CFAbsoluteTime time; 1529 } nstate; 1530 __Check_Compile_Time(sizeof(nstate.time) <= sizeof(nstate.u64)); 1531 1532 nstate.u64 = 0; 1533 nstate.time = *gLastWakeTime; 1534 notify_set_state(gLastWakeTimeToken, nstate.u64); 1535 } 1536 if (gLastSMCS3S0WakeIntervalToken >= 0) 1537 notify_set_state(gLastSMCS3S0WakeIntervalToken, wakeup_smc_result); 1538#endif 1539exit: 1540 return; 1541} 1542 1543static void calendarRTCDidResync(CFMachPortRef port, void *msg, CFIndex size, void *info) 1544{ 1545 mach_msg_header_t *header = (mach_msg_header_t *)msg; 1546 1547 if (!header || HOST_CALENDAR_CHANGED_REPLYID != header->msgh_id) { 1548 return; 1549 } 1550 1551 // renew our request for calendar change notification 1552 (void) host_request_notification(mach_host_self(), HOST_NOTIFY_CALENDAR_CHANGE, 1553 header->msgh_local_port); 1554 1555 calendarRTCDidResync_getSMCWakeInterval(); 1556 AutoWakeCalendarChange(); 1557 1558 return; 1559} 1560 1561/* MIG CALL 1562 * Returns last wake time to a querulous process 1563 */ 1564kern_return_t _io_pm_last_wake_time( 1565 mach_port_t server, 1566 vm_offset_t *out_wake_data, 1567 mach_msg_type_number_t *out_wake_len, 1568 vm_offset_t *out_delta_data, 1569 mach_msg_type_number_t *out_delta_len, 1570 int *return_val) 1571{ 1572 *out_wake_len = 0; 1573 *out_delta_len = 0; 1574 *return_val = kIOReturnInvalid; 1575 1576 if (gExpectingWakeFromSleepClockResync) { 1577 *return_val = kIOReturnNotReady; 1578 return KERN_SUCCESS; 1579 } 1580 1581#if !TARGET_OS_EMBEDDED 1582 if (!gSMCSupportsWakeupTimer) { 1583 *return_val = kIOReturnNotFound; 1584 return KERN_SUCCESS; 1585 }; 1586#endif 1587 1588 *out_wake_data = (vm_offset_t)gLastWakeTime; 1589 *out_wake_len = sizeof(*gLastWakeTime); 1590 *out_delta_data = (vm_offset_t)gLastSMCS3S0WakeInterval; 1591 *out_delta_len = sizeof(*gLastSMCS3S0WakeInterval); 1592 1593 *return_val = kIOReturnSuccess; 1594 1595 return KERN_SUCCESS; 1596} 1597 1598 1599/* displayMatched 1600 * 1601 * Notification fires when IODisplayWranger object is created in the IORegistry. 1602 * 1603 */ 1604static void displayMatched( 1605 void *note_port_in, 1606 io_iterator_t iter) 1607{ 1608 IONotificationPortRef note_port = (IONotificationPortRef)note_port_in; 1609 io_service_t wrangler = MACH_PORT_NULL; 1610 io_object_t dimming_notification_object = MACH_PORT_NULL; 1611 1612 if((wrangler = (io_registry_entry_t)IOIteratorNext(iter))) 1613 { 1614 IOServiceAddInterestNotification( 1615 note_port, 1616 wrangler, 1617 kIOGeneralInterest, 1618 displayPowerStateChange, 1619 NULL, 1620 &dimming_notification_object); 1621 1622 IOObjectRelease(wrangler); 1623 } 1624 1625} 1626 1627 1628static void 1629initializeShutdownNotifications(void) 1630{ 1631 CFMachPortRef gNotifyMachPort = NULL; 1632 CFRunLoopSourceRef gNotifyMachPortRLS = NULL; 1633 mach_port_t our_port = MACH_PORT_NULL; 1634 1635 // Tell the kernel that we are NOT shutting down at the moment, since 1636 // configd is just launching now. 1637 // Why: if configd crashed with "System Shutdown" == kCFbooleanTrue, reset 1638 // it now as the situation may no longer apply. 1639 _setRootDomainProperty(CFSTR("System Shutdown"), kCFBooleanFalse); 1640 1641 /* * * * * * * * * * * * * */ 1642 1643 // Sneak in our registration for CPU power notifications here; to piggy-back 1644 // with the other mach port registrations for LW. 1645 notify_register_mach_port( 1646 kIOPMCPUPowerNotificationKey, 1647 &our_port, 1648 0, /* flags */ 1649 &gCPUPowerNotificationToken); 1650 1651 1652 notify_register_mach_port( 1653 kLWShutdowntInitiated, 1654 &our_port, 1655 NOTIFY_REUSE, /* flags */ 1656 &lwNotify.shutdown); 1657 1658 notify_register_mach_port( 1659 kLWRestartInitiated, 1660 &our_port, 1661 NOTIFY_REUSE, /* flags */ 1662 &lwNotify.restart); 1663 1664 notify_register_mach_port( 1665 kLWLogoutCancelled, 1666 &our_port, 1667 NOTIFY_REUSE, /* flags */ 1668 &lwNotify.cancel); 1669 1670 notify_register_mach_port( 1671 kLWLogoutPointOfNoReturn, 1672 &our_port, 1673 NOTIFY_REUSE, /* flags */ 1674 &lwNotify.pointofnoreturn); 1675 notify_register_mach_port( 1676 kLWSULogoutInitiated, 1677 &our_port, 1678 NOTIFY_REUSE, /* flags */ 1679 &lwNotify.su); 1680 1681 /* * * * * * * * * * * * * */ 1682 1683 gNotifyMachPort = _SC_CFMachPortCreateWithPort( 1684 "PowerManagement/shutdown", 1685 our_port, 1686 lwShutdownCallback, 1687 NULL); 1688 1689 if (gNotifyMachPort) { 1690 gNotifyMachPortRLS = CFMachPortCreateRunLoopSource(0, gNotifyMachPort, 0); 1691 if (gNotifyMachPortRLS) { 1692 CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotifyMachPortRLS, kCFRunLoopDefaultMode); 1693 CFRelease(gNotifyMachPortRLS); 1694 } 1695 CFRelease(gNotifyMachPort); 1696 } 1697} 1698 1699#if !TARGET_OS_EMBEDDED 1700static void handleDWThermalMsg(CFStringRef wakeType) 1701{ 1702 CFMutableDictionaryRef options = NULL; 1703 1704 if (wakeType == NULL) 1705 getPlatformWakeReason(NULL, &wakeType); 1706 1707 if ( (isA_BTMtnceWake() || isA_SleepSrvcWake()) && !isA_NotificationDisplayWake() && 1708 (CFEqual(wakeType, kIOPMRootDomainWakeTypeMaintenance) || 1709 CFEqual(wakeType, kIOPMRootDomainWakeTypeSleepService)) 1710#if TCPKEEPALIVE 1711 && !((getTCPKeepAliveState(NULL, 0) == kActive) && checkForActivesByType(kInteractivePushServiceType)) ) { 1712#else 1713 ) { 1714#endif 1715 1716 // If system woke up for PowerNap and system is in a power nap wake, without any notifications 1717 // being displayed, then let system go to sleep 1718 options = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, 1719 &kCFTypeDictionaryValueCallBacks); 1720 if (options) { 1721 CFDictionarySetValue(options, CFSTR("Sleep Reason"), CFSTR(kIOPMDarkWakeThermalEmergencyKey)); 1722 } 1723 IOPMSleepSystemWithOptions(getRootDomainConnect(), options); 1724 if (options) CFRelease(options); 1725 } 1726 else { 1727 // For all other cases, let system run in non-silent running mode 1728 _unclamp_silent_running(true); 1729 logASLMessageIgnoredDWTEmergency(); 1730 } 1731} 1732#endif 1733 1734 1735static void 1736RootDomainInterest( 1737 void *refcon, 1738 io_service_t root_domain, 1739 natural_t messageType, 1740 void *messageArgument) 1741{ 1742 static CFStringRef _uuidString = NULL; 1743#if !TARGET_OS_EMBEDDED 1744 CFStringRef wakeReason = NULL, wakeType = NULL; 1745#endif 1746 1747 if (messageType == kIOPMMessageDriverAssertionsChanged) 1748 { 1749 CFNumberRef driverAssertions = 0; 1750 uint32_t _driverAssertions = 0; 1751 1752 // Read driver assertion status 1753 driverAssertions = IORegistryEntryCreateCFProperty(getRootDomain(), CFSTR(kIOPMAssertionsDriverKey), 0, 0); 1754 1755 if (driverAssertions) { 1756 CFNumberGetValue(driverAssertions, kCFNumberIntType, &_driverAssertions); 1757 _PMAssertionsDriverAssertionsHaveChanged(_driverAssertions); 1758 CFRelease(driverAssertions); 1759 } 1760 } 1761 1762 if (messageType == kIOPMMessageSystemPowerEventOccurred) 1763 { 1764 // Let System Events know about just-occurred thermal state change 1765 1766 PMSystemEventsRootDomainInterest(); 1767 } 1768 1769#if !TARGET_OS_EMBEDDED 1770 if(messageType == kIOPMMessageDarkWakeThermalEmergency) 1771 { 1772 mt2RecordThermalEvent(kThermalStateSleepRequest); 1773 _darkWakeThermalEventCount++; 1774 1775 getPlatformWakeReason(&wakeReason, &wakeType); 1776 if (CFEqual(wakeReason, CFSTR("")) && CFEqual(wakeType, CFSTR(""))) 1777 { 1778 // Thermal emergency msg is received too early before wake type is 1779 // determined. Delay the handler for a short handler until we know 1780 // the wake type 1781 if (gDWTMsgDispatch) 1782 dispatch_suspend(gDWTMsgDispatch); 1783 else { 1784 gDWTMsgDispatch = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 1785 0, dispatch_get_main_queue()); 1786 dispatch_source_set_event_handler(gDWTMsgDispatch, ^{ 1787 handleDWThermalMsg(NULL); 1788 }); 1789 1790 dispatch_source_set_cancel_handler(gDWTMsgDispatch, ^{ 1791 if (gDWTMsgDispatch) { 1792 dispatch_release(gDWTMsgDispatch); 1793 gDWTMsgDispatch = 0; 1794 } 1795 }); 1796 } 1797 1798 dispatch_source_set_timer(gDWTMsgDispatch, 1799 dispatch_walltime(NULL, kDWTMsgHandlerDelay * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); 1800 dispatch_resume(gDWTMsgDispatch); 1801 } 1802 else 1803 { 1804 handleDWThermalMsg(wakeType); 1805 CFRunLoopPerformBlock(_getPMRunLoop(), kCFRunLoopDefaultMode, 1806 ^{ logASLAssertionTypeSummary(kInteractivePushServiceType);}); 1807 CFRunLoopWakeUp(_getPMRunLoop()); 1808 } 1809 1810 } 1811#endif 1812 1813 if (messageType == kIOPMMessageFeatureChange) 1814 { 1815 // Let PMSettings code know that some settings may have been 1816 // added or removed. 1817 1818 PMSettingsSupportedPrefsListHasChanged(); 1819 } 1820 1821 if (messageType == kIOPMMessageSleepWakeUUIDChange) 1822 { 1823 if (kIOPMMessageSleepWakeUUIDSet == messageArgument) 1824 { 1825 // We keep a copy of the newly published UUID string 1826 _uuidString = IOPMSleepWakeCopyUUID(); 1827 1828 // xnu kernel PM has just published a sleep/Wake UUID. 1829 // We must replenish it with a new one (which we generate in user space) 1830 // Kernel PM will use the UUID we provide here on the next sleep/wake event. 1831 pushNewSleepWakeUUID(); 1832 1833 } else 1834 if (kIOPMMessageSleepWakeUUIDCleared == messageArgument) 1835 { 1836 // UUID cleared 1837 if (_uuidString) { 1838 // We're ready to parse out the newly acquired Power log and 1839 // package events that pertain to the current UUID 1840 CFRelease(_uuidString); 1841 _uuidString = NULL; 1842 } 1843 1844 // The kernel will have begun using its cached UUID (the one that we just stored) 1845 // for its power events log. We need to replenish its (now empty) cache with another 1846 // UUID, which in turn will get used when the current one expires 1847 1848 pushNewSleepWakeUUID(); 1849 1850 } 1851 } 1852 1853 if (messageType == kIOPMMessageUserIsActiveChanged) 1854 { 1855 userActiveHandleRootDomainActivity(); 1856 } 1857} 1858 1859static void 1860initializeRootDomainInterestNotifications(void) 1861{ 1862 IONotificationPortRef note_port = MACH_PORT_NULL; 1863 CFRunLoopSourceRef runLoopSrc = NULL; 1864 io_service_t root_domain = MACH_PORT_NULL; 1865 io_object_t notification_object = MACH_PORT_NULL; 1866 IOReturn ret; 1867 1868 root_domain = IORegistryEntryFromPath(kIOMasterPortDefault, 1869 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); 1870 1871 if(!root_domain) return; 1872 1873 note_port = IONotificationPortCreate(MACH_PORT_NULL); 1874 if(!note_port) goto exit; 1875 1876 ret = IOServiceAddInterestNotification(note_port, root_domain, 1877 kIOGeneralInterest, RootDomainInterest, 1878 NULL, ¬ification_object); 1879 if (ret != kIOReturnSuccess) goto exit; 1880 1881 runLoopSrc = IONotificationPortGetRunLoopSource(note_port); 1882 1883 if (runLoopSrc) 1884 { 1885 CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSrc, kCFRunLoopDefaultMode); 1886 } 1887 1888exit: 1889 // Do not release notification_object, would uninstall notification 1890 // Do not release runLoopSrc because it's 'owned' by note_port, and both 1891 // must be kept around to receive this notification 1892 if(MACH_PORT_NULL != root_domain) IOObjectRelease(root_domain); 1893} 1894 1895#if !TARGET_OS_EMBEDDED 1896static void initializeUserNotifications(void) 1897{ 1898 SCDynamicStoreRef localStore = _getSharedPMDynamicStore(); 1899 CFArrayRef keys = NULL; 1900 1901 gConsoleNotifyKey = SCDynamicStoreKeyCreateConsoleUser(NULL); 1902 if (gConsoleNotifyKey) 1903 { 1904 keys = CFArrayCreate(NULL, (const void **)&gConsoleNotifyKey, 1905 1, &kCFTypeArrayCallBacks); 1906 1907 if (keys) { 1908 SCDynamicStoreSetNotificationKeys(localStore, keys, NULL); 1909 CFRelease(keys); 1910 } 1911 } 1912 1913 SystemLoadUserStateHasChanged(); 1914} 1915 1916static void enableSleepWakeWdog() 1917{ 1918 io_service_t rootDomainService = IO_OBJECT_NULL; 1919 io_connect_t rotDomainConnect = IO_OBJECT_NULL; 1920 kern_return_t kr = 0; 1921 IOReturn ret; 1922 1923 // Check if system supports NTS 1924 if (IONoteToSelfSupported() == false) 1925 return; 1926 1927 // Find it 1928 rootDomainService = getRootDomain(); 1929 if (IO_OBJECT_NULL == rootDomainService) { 1930 goto exit; 1931 } 1932 1933 // Open it 1934 kr = IOServiceOpen(rootDomainService, mach_task_self(), 0, &rotDomainConnect); 1935 if (KERN_SUCCESS != kr) { 1936 goto exit; 1937 } 1938 1939 ret = IOConnectCallMethod(rotDomainConnect, kPMSleepWakeWatchdogEnable, 1940 NULL, 0, 1941 NULL, 0, NULL, 1942 NULL, NULL, NULL); 1943 1944 if (kIOReturnSuccess != ret) 1945 { 1946 goto exit; 1947 } 1948 1949exit: 1950 if (IO_OBJECT_NULL != rotDomainConnect) 1951 IOServiceClose(rotDomainConnect); 1952 1953} 1954 1955#endif 1956 1957static void initializeSleepWakeNotifications(void) 1958{ 1959 IONotificationPortRef notify; 1960 io_object_t anIterator; 1961 1962 _pm_ack_port = IORegisterForSystemPower(0, ¬ify, 1963 SleepWakeCallback, &anIterator); 1964 1965 if ( _pm_ack_port != MACH_PORT_NULL ) { 1966 if(notify) CFRunLoopAddSource(CFRunLoopGetCurrent(), 1967 IONotificationPortGetRunLoopSource(notify), 1968 kCFRunLoopDefaultMode); 1969 } 1970} 1971 1972