1/* 2 * Copyright (c) 2004, 2012 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#include <CoreFoundation/CFXPCBridge.h> 26#include <TargetConditionals.h> 27#include <IOKit/IOKitLib.h> 28#include <IOKit/pwr_mgt/IOPMPrivate.h> 29#include <IOKit/pwr_mgt/IOPMLib.h> 30#include <mach/mach_init.h> 31#include <mach/mach_port.h> 32#include <mach/vm_map.h> 33#include <servers/bootstrap.h> 34#include <bootstrap_priv.h> 35#include <sys/types.h> 36#include <sys/sysctl.h> 37#include <notify.h> 38#include "IOSystemConfiguration.h" 39#include "IOPMLibPrivate.h" 40#include "powermanagement.h" 41#include <asl.h> 42#include <xpc/xpc.h> 43 44#include <unistd.h> 45#include <stdlib.h> 46#include <dirent.h> 47#include <pthread.h> 48 49 50#define pwrLogDirName "/System/Library/PowerEvents" 51 52static const int kMaxNameLength = 128; 53static mach_port_t powerd_connection = MACH_PORT_NULL; 54static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 55 56static void _reset_connection( ) 57{ 58 pthread_mutexattr_t attr; 59 60 powerd_connection = MACH_PORT_NULL; 61 pthread_mutexattr_init(&attr); 62 pthread_mutex_init(&lock, &attr); 63} 64 65IOReturn _pm_connect(mach_port_t *newConnection) 66{ 67 kern_return_t kern_result = KERN_SUCCESS; 68 IOReturn ret = kIOReturnSuccess; 69 70 if(!newConnection) return kIOReturnBadArgument; 71 if (powerd_connection != MACH_PORT_NULL) { 72 *newConnection = powerd_connection; 73 74 return kIOReturnSuccess; 75 } 76 77 pthread_mutex_lock(&lock); 78 79 // Check again and see if the port is created by another thread 80 if (powerd_connection != MACH_PORT_NULL) { 81 *newConnection = powerd_connection; 82 goto exit; 83 } 84 // open reference to powerd 85 kern_result = bootstrap_look_up2(bootstrap_port, 86 kIOPMServerBootstrapName, 87 &powerd_connection, 88 0, 89 BOOTSTRAP_PRIVILEGED_SERVER); 90 if(KERN_SUCCESS != kern_result) { 91 *newConnection = powerd_connection = MACH_PORT_NULL; 92 asl_log(NULL, NULL, ASL_LEVEL_ERR, 93 "bootstrap_look_up2 failed with 0x%x\n", kern_result); 94 ret = kIOReturnError; 95 goto exit; 96 } 97 *newConnection = powerd_connection; 98 if (pthread_atfork(NULL, NULL, _reset_connection) != 0) 99 powerd_connection = MACH_PORT_NULL; 100 101exit: 102 pthread_mutex_unlock(&lock); 103 104 return ret; 105} 106 107IOReturn _pm_disconnect(mach_port_t connection __unused) 108{ 109 // Do nothing. We re-use the mach port 110 return kIOReturnSuccess; 111} 112 113 114bool IOPMUserIsActive(void) 115{ 116 io_service_t service = IO_OBJECT_NULL; 117 CFBooleanRef userIsActiveBool = NULL; 118 bool ret_val = false; 119 120 service = IORegistryEntryFromPath(kIOMasterPortDefault, 121 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); 122 123 if (IO_OBJECT_NULL != service) { 124 userIsActiveBool = IORegistryEntryCreateCFProperty( 125 service, 126 CFSTR(kIOPMUserIsActiveKey), 127 kCFAllocatorDefault, 0); 128 IOObjectRelease(service); 129 } 130 131 ret_val = (kCFBooleanTrue == userIsActiveBool); 132 133 if (userIsActiveBool) { 134 CFRelease(userIsActiveBool); 135 } 136 return ret_val; 137} 138 139typedef struct { 140// UserActive 141 void (^callblock_bool)(bool); 142 IONotificationPortRef notify; 143 io_object_t letItGo; 144// UserActivityLevel 145 void (^callblock_activity)(uint64_t, uint64_t); 146 int dtoken; 147} _UserActiveNotification; 148 149void IOPMUserDidChangeCallback( 150 void *refcon __unused, 151 io_service_t service __unused, 152 uint32_t messageType, 153 void *messageArgument __unused) 154{ 155 _UserActiveNotification *_useractive = (_UserActiveNotification *)refcon; 156 157 if (_useractive && (messageType == kIOPMMessageUserIsActiveChanged)) 158 { 159 _useractive->callblock_bool( IOPMUserIsActive() ); 160 } 161} 162 163 164IOPMNotificationHandle IOPMScheduleUserActiveChangedNotification(dispatch_queue_t queue, void (^block)(bool)) 165{ 166 _UserActiveNotification *_useractive = NULL; 167 io_registry_entry_t service = IO_OBJECT_NULL; 168 kern_return_t kr = KERN_INVALID_VALUE; 169 170 _useractive = calloc(1, sizeof(_UserActiveNotification)); 171 172 if (_useractive) 173 { 174 _useractive->callblock_bool = Block_copy(block); 175 176 _useractive->notify = IONotificationPortCreate(MACH_PORT_NULL); 177 if (_useractive->notify) { 178 IONotificationPortSetDispatchQueue(_useractive->notify, queue); 179 } 180 181 service = IORegistryEntryFromPath(kIOMasterPortDefault, 182 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); 183 184 kr = IOServiceAddInterestNotification( 185 _useractive->notify, service, kIOGeneralInterest, 186 IOPMUserDidChangeCallback, (void *)_useractive, &_useractive->letItGo); 187 188 IOObjectRelease(service); 189 } 190 191 if (kIOReturnSuccess != kr) { 192 IOPMUnregisterNotification((IOPMNotificationHandle)_useractive); 193 _useractive = NULL; 194 } 195 196 return _useractive; 197} 198 199void IOPMUnregisterNotification(IOPMNotificationHandle handle) 200{ 201 _UserActiveNotification *_useractive = (_UserActiveNotification *)handle; 202 203 if (_useractive) 204 { 205 if (_useractive->callblock_bool) { 206 Block_release(_useractive->callblock_bool); 207 } 208 if (_useractive->notify) { 209 IONotificationPortDestroy(_useractive->notify); 210 } 211 if (IO_OBJECT_NULL != _useractive->letItGo) { 212 IOObjectRelease(_useractive->letItGo); 213 } 214 if (_useractive->dtoken) { 215 notify_cancel(_useractive->dtoken); 216 } 217 bzero(_useractive, sizeof(_useractive)); 218 free(_useractive); 219 } 220} 221 222 223static void decodeUserActivityLevel64(uint64_t in, 224 uint64_t *outActive, 225 uint64_t *outMSA) 226{ 227 if (outActive) { 228 *outActive = in; 229 } 230 if (outMSA) { 231 *outMSA = in ? (in & (1 << (ffsl(in)-1))) : 0; 232 } 233} 234 235 236IOReturn IOPMGetUserActivityLevel(uint64_t *outUserActive, 237 uint64_t *mostSignificantActivity) 238{ 239 int token = 0; 240 uint64_t payload = 0; 241 uint32_t r = 0; 242 243 r = notify_register_check("com.apple.system.powermanagement.useractivity2", 244 &token); 245 246 if (NOTIFY_STATUS_OK == r) 247 { 248 notify_get_state(token, &payload); 249 notify_cancel(token); 250 } 251 252 decodeUserActivityLevel64(payload, 253 outUserActive, 254 mostSignificantActivity); 255 256 257 return kIOReturnSuccess; 258} 259 260IOPMNotificationHandle IOPMScheduleUserActivityLevelNotification(dispatch_queue_t queue, 261 void (^inblock)(uint64_t, uint64_t)) 262{ 263 _UserActiveNotification *_useractive = NULL; 264 uint32_t r = 0; 265 266 _useractive = calloc(1, sizeof(_UserActiveNotification)); 267 268 if (_useractive) 269 { 270 notify_handler_t calloutBlock = ^(int token) 271 { 272 uint64_t data = 0; 273 uint64_t active = 0; 274 uint64_t most = 0; 275 uint32_t r2; 276 277 r2 = notify_get_state(token, &data); 278 if (NOTIFY_STATUS_OK == r2) 279 { 280 decodeUserActivityLevel64(data, &active, &most); 281 282 if (_useractive) 283 inblock(active, most); 284 } 285 }; 286 287 r = notify_register_dispatch("com.apple.system.powermanagement.useractivity2", 288 &_useractive->dtoken, 289 queue, 290 calloutBlock); 291 if (NOTIFY_STATUS_OK != r) { 292 free(_useractive); 293 _useractive = NULL; 294 } 295 } 296 297 return _useractive; 298} 299 300 301CFStringRef IOPMCopyUserActivityLevelDescription(uint64_t userActive) 302{ 303 int prev = 0; 304 CFMutableStringRef result = CFStringCreateMutable(0, 0); 305 306 if (0==userActive) { 307 CFStringAppend(result, CFSTR("Inactive")); 308 goto exit; 309 } 310 311 if (kIOPMUserPresentActive & userActive) { 312 if (prev++) CFStringAppend(result,CFSTR(" ")); 313 CFStringAppend(result, CFSTR("PresentActive")); 314 } 315 if (kIOPMUserPresentPassive & userActive) { 316 if (prev++) CFStringAppend(result,CFSTR(" ")); 317 CFStringAppend(result, CFSTR("PresentPassive")); 318 } 319 if (kIOPMUserRemoteClientActive & userActive) { 320 if (prev++) CFStringAppend(result,CFSTR(" ")); 321 CFStringAppend(result, CFSTR("RemoteActive")); 322 } 323 if (kIOPMUserNotificationActive & userActive) { 324 if (prev++) CFStringAppend(result,CFSTR(" ")); 325 CFStringAppend(result, CFSTR("NotificationActive")); 326 } 327exit: 328 return result; 329} 330 331 332 333/*****************************************************************************/ 334/*****************************************************************************/ 335 336/****************************************************************************** 337 * IOPMCopyHIDPostEventHistory 338 * 339 ******************************************************************************/ 340 341IOReturn IOPMCopyHIDPostEventHistory(CFArrayRef *outArray) 342{ 343 CFDataRef serializedData = NULL; 344 vm_address_t outBuffer = 0; 345 vm_size_t outSize = 0; 346 mach_port_t pmserverport = MACH_PORT_NULL; 347 IOReturn ret = kIOReturnError; 348 int history_return = 0; 349 350 if (kIOReturnSuccess != _pm_connect(&pmserverport)) 351 goto exit; 352 353 if (KERN_SUCCESS != io_pm_hid_event_copy_history(pmserverport, 354 &outBuffer, (mach_msg_type_number_t *) &outSize, &history_return)) 355 { 356 goto exit; 357 } 358 359 serializedData = CFDataCreate(0, (const UInt8 *)outBuffer, outSize); 360 if (serializedData) { 361 *outArray = (CFArrayRef)CFPropertyListCreateWithData(0, serializedData, 0, NULL, NULL); 362 CFRelease(serializedData); 363 } 364 365 if (*outArray) 366 ret = kIOReturnSuccess; 367 368 vm_deallocate(mach_task_self(), outBuffer, outSize); 369 _pm_disconnect(pmserverport); 370exit: 371 return ret; 372} 373 374/****************************************************************************** 375 * IOPMGetLastWakeTime 376 * 377 ******************************************************************************/ 378 379IOReturn IOPMGetLastWakeTime( 380 CFAbsoluteTime *lastWakeTimeOut, 381 CFTimeInterval *adjustedForPhysicalWakeOut) 382{ 383 IOReturn ret; 384 CFTimeInterval lastSMCS3S0WakeInterval = 0.0; 385 CFAbsoluteTime lastWakeTime; 386 struct timeval rawLastWakeTime; 387 size_t rawLastWakeTimeSize = sizeof(rawLastWakeTime); 388 389 if (!lastWakeTimeOut || !adjustedForPhysicalWakeOut) { 390 return kIOReturnBadArgument; 391 } 392 393 *lastWakeTimeOut = 0.0; 394 *adjustedForPhysicalWakeOut = 0.0; 395 396 ret = sysctlbyname("kern.waketime", &rawLastWakeTime, &rawLastWakeTimeSize, NULL, 0); 397 if (ret || !rawLastWakeTime.tv_sec) { 398 return kIOReturnNotReady; 399 } 400 401 // Convert the timeval, which is in UNIX time, to a CFAbsoluteTime 402 lastWakeTime = rawLastWakeTime.tv_sec + (rawLastWakeTime.tv_usec / 1000000.0); 403 lastWakeTime -= kCFAbsoluteTimeIntervalSince1970; 404 405 406 *lastWakeTimeOut = lastWakeTime; 407 *adjustedForPhysicalWakeOut = lastSMCS3S0WakeInterval; 408 409 return kIOReturnSuccess; 410} 411 412 413#pragma mark - 414#pragma mark API 415 416/****************************************************************************** 417 * IOPMCopyPowerHistory 418 * 419 ******************************************************************************/ 420IOReturn IOPMCopyPowerHistory(CFArrayRef *outArray) 421{ 422 DIR *dp; 423 struct dirent *ep; 424 425 CFMutableArrayRef logs = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); 426 427 dp = opendir(pwrLogDirName); 428 if(dp == NULL) 429 return kIOReturnError; 430 431 CFMutableDictionaryRef uuid_details; 432 CFStringRef uuid; 433 CFStringRef timestamp; 434 435 char *tok; 436 char *d_name; 437 int fileCount = 0; 438 439 while ((ep = readdir(dp))) { 440 if(!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..")) 441 continue; 442 else 443 fileCount++; 444 445 uuid_details = CFDictionaryCreateMutable(kCFAllocatorDefault, 446 0, 447 &kCFTypeDictionaryKeyCallBacks, 448 &kCFTypeDictionaryValueCallBacks); 449 d_name = strdup(ep->d_name); 450 451 // Parse filename for metadata 452 int part = 1; 453 while((tok = strsep(&d_name, "_")) != NULL) { 454 455 if(part == 1) { 456 timestamp = CFStringCreateWithCString(kCFAllocatorDefault, 457 tok, 458 kCFStringEncodingUTF8); 459 CFDictionarySetValue(uuid_details, 460 CFSTR(kIOPMPowerHistoryTimestampKey), 461 timestamp); 462 CFRelease(timestamp); 463 } 464 else if(part == 2) { 465 uuid = CFStringCreateWithCString(kCFAllocatorDefault, 466 tok, 467 kCFStringEncodingUTF8); 468 CFDictionarySetValue(uuid_details, 469 CFSTR(kIOPMPowerHistoryUUIDKey), 470 uuid); 471 CFRelease(uuid); 472 } 473 else if(part == 3) { 474 // We don't want the extension .plog to be part of the 475 // timestamp 476 tok = strsep(&tok, "."); 477 timestamp = CFStringCreateWithCString(kCFAllocatorDefault, 478 tok, 479 kCFStringEncodingUTF8); 480 CFDictionarySetValue(uuid_details, 481 CFSTR(kIOPMPowerHistoryTimestampCompletedKey), 482 timestamp); 483 CFRelease(timestamp); 484 } 485 486 part++; 487 } 488 489 CFArrayAppendValue(logs, uuid_details); 490 CFRelease(uuid_details); 491 free(d_name); 492 } 493 494 closedir(dp); 495 496 if(fileCount == 0) { 497 *outArray = NULL; 498 return kIOReturnNotFound; 499 } 500 else 501 *outArray = logs; 502 503 return kIOReturnSuccess; 504} 505 506 507/****************************************************************************** 508 * IOPMCopyPowerHistoryDetailed 509 * 510 ******************************************************************************/ 511IOReturn IOPMCopyPowerHistoryDetailed(CFStringRef UUID, CFDictionaryRef *details)//CFArrayRef *outArray) 512{ 513 IOReturn return_code = kIOReturnBadArgument; 514 CFDataRef serializedData = NULL; 515 char uuid_cstr[kMaxNameLength]; 516 517 CFURLRef fileURL = NULL; 518 CFMutableStringRef fileName = CFStringCreateMutable( 519 kCFAllocatorDefault, 520 255); 521 522 CFStringAppend(fileName, CFSTR(pwrLogDirName)); 523 CFStringAppend(fileName, CFSTR("/")); 524 525 if (NULL == details || NULL == UUID) { 526 goto exit; 527 } 528 529 *details = NULL; 530 531 if (!CFStringGetCString(UUID, uuid_cstr, sizeof(uuid_cstr), kCFStringEncodingMacRoman)) { 532 goto exit; 533 } 534 535 DIR *dp; 536 struct dirent *ep; 537 538 dp = opendir(pwrLogDirName); 539 540 if(dp == NULL) { 541 return_code = kIOReturnError; 542 goto exit; 543 } 544 545 while ((ep = readdir(dp))) { 546 if(strstr(ep->d_name, uuid_cstr)) { 547 CFStringRef uuid_file = CFStringCreateWithCString( 548 kCFAllocatorDefault, 549 ep->d_name, 550 kCFStringEncodingUTF8); 551 CFStringAppend(fileName, uuid_file); 552 fileURL = CFURLCreateWithFileSystemPath( 553 kCFAllocatorDefault, 554 fileName, 555 kCFURLPOSIXPathStyle, 556 false); 557 558 CFRelease(uuid_file); 559 } 560 } 561 562 closedir(dp); 563 564 if(!fileURL) { 565 return_code = kIOReturnError; 566 goto exit; 567 } 568 SInt32 errorCode; 569 Boolean status = CFURLCreateDataAndPropertiesFromResource( 570 kCFAllocatorDefault, 571 fileURL, 572 &serializedData, 573 NULL, 574 NULL, 575 &errorCode); 576 577 if (serializedData && status) { 578 *details = (CFDictionaryRef)CFPropertyListCreateWithData(0, serializedData, 0, NULL, NULL); 579 CFRelease(serializedData); 580 } 581 582 if (NULL == details) { 583 return_code = kIOReturnError; 584 } else { 585 return_code = kIOReturnSuccess; 586 } 587 588 CFRelease(fileURL); 589 CFRelease(fileName); 590 591exit: 592 return return_code; 593} 594 595/****************************************************************************** 596 * IOPMSetSleepServiceCapTimeout 597 * 598 ******************************************************************************/ 599IOReturn IOPMSetSleepServicesWakeTimeCap(CFTimeInterval cap) 600{ 601 mach_port_t pm_server = MACH_PORT_NULL; 602 kern_return_t return_code = KERN_SUCCESS; 603 int pm_mig_return = -1; 604 605 return_code = _pm_connect(&pm_server); 606 607 if(kIOReturnSuccess != return_code) { 608 return return_code; 609 } 610 611 return_code = io_pm_set_sleepservice_wake_time_cap(pm_server, (int)cap, &pm_mig_return); 612 613 _pm_disconnect(pm_server); 614 if (pm_mig_return == kIOReturnSuccess) 615 return return_code; 616 else 617 return pm_mig_return; 618} 619 620/****************************************************************************** 621 * IOPMSleepWakeSetUUID 622 * 623 ******************************************************************************/ 624IOReturn IOPMSleepWakeSetUUID(CFStringRef newUUID) 625{ 626 IOReturn ret = kIOReturnSuccess; 627 io_service_t service = IO_OBJECT_NULL; 628 CFTypeRef setObject = NULL; 629 630 if (!newUUID) { 631 // Clear active UUID 632 setObject = kCFBooleanFalse; 633 } else { 634 // cache the upcoming UUID 635 setObject = newUUID; 636 } 637 638 service = IORegistryEntryFromPath(kIOMasterPortDefault, 639 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); 640 641 if (IO_OBJECT_NULL != service) { 642 ret = IORegistryEntrySetCFProperty( 643 service, CFSTR(kIOPMSleepWakeUUIDKey), 644 setObject); 645 IOObjectRelease(service); 646 } 647 return ret; 648} 649 650/****************************************************************************** 651 * IOPMSleepWakeCopyUUID 652 * 653 ******************************************************************************/ 654CFStringRef IOPMSleepWakeCopyUUID(void) 655{ 656 CFStringRef uuidString = NULL; 657 io_service_t service = IO_OBJECT_NULL; 658 659 service = IORegistryEntryFromPath(kIOMasterPortDefault, 660 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); 661 662 if (IO_OBJECT_NULL != service) { 663 uuidString = IORegistryEntryCreateCFProperty( 664 service, 665 CFSTR(kIOPMSleepWakeUUIDKey), 666 kCFAllocatorDefault, 0); 667 IOObjectRelease(service); 668 } 669 670 // Caller must release uuidString, if non-NULL 671 return uuidString; 672} 673 674 675bool IOPMGetUUID(int whichUUID, char *putTheUUIDHere, int sizeOfBuffer) 676{ 677 bool return_bool_value = false; 678 679 if (kIOPMSleepWakeUUID == whichUUID) 680 { 681 CFStringRef bs = IOPMSleepWakeCopyUUID(); 682 if (bs) { 683 Boolean bool_result; 684 bool_result = CFStringGetCString(bs, putTheUUIDHere, sizeOfBuffer, kCFStringEncodingUTF8); 685 CFRelease(bs); 686 return bool_result; 687 } 688 return false; 689 } 690 else if (kIOPMSleepServicesUUID == whichUUID) 691 { 692 mach_port_t pm_server = MACH_PORT_NULL; 693 kern_return_t return_code = KERN_SUCCESS; 694 char strPtr[kPMMIGStringLength]; 695 int pm_mig_return = -1; 696 697 return_code = _pm_connect(&pm_server); 698 699 if(kIOReturnSuccess != return_code) { 700 return false; 701 } 702 703 bzero(strPtr, sizeof(strPtr)); 704 return_code = io_pm_get_uuid(pm_server, kIOPMSleepServicesUUID, strPtr, &pm_mig_return); 705 706 if ((KERN_SUCCESS == return_code) && (KERN_SUCCESS == pm_mig_return)) 707 { 708 bzero(putTheUUIDHere, sizeOfBuffer); 709 710 strncpy(putTheUUIDHere, strPtr, sizeOfBuffer-1); 711 712 return_bool_value = true; 713 } 714 715 _pm_disconnect(pm_server); 716 } 717 718 return return_bool_value; 719} 720 721/****************************************************************************** 722 * IOPMDebugTracePoint 723 * 724 ******************************************************************************/ 725IOReturn IOPMDebugTracePoint(CFStringRef facility, uint8_t *data, int dataCount) 726{ 727 io_registry_entry_t gRoot = IO_OBJECT_NULL; 728 CFNumberRef setNum = NULL; 729 IOReturn ret = kIOReturnError; 730 if (data == NULL || facility == NULL || 1 != dataCount) 731 return kIOReturnBadArgument; 732 733 gRoot = IORegistryEntryFromPath( kIOMasterPortDefault, 734 kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); 735 736 if (IO_OBJECT_NULL == gRoot) 737 return kIOReturnError; 738 739 // We allow CF to treat this number as a signed integer. We're using it as a bitfield; 740 // we shouldn't have to worry about sign extension when it gets unpacked. 741 setNum = CFNumberCreate(0, kCFNumberSInt8Type, data); 742 if (!setNum) 743 goto exit; 744 745 ret = IORegistryEntrySetCFProperty( gRoot, 746 CFSTR(kIOPMLoginWindowSecurityDebugKey), 747 setNum); 748exit: 749 if (setNum) 750 CFRelease(setNum); 751 if (gRoot) 752 IOObjectRelease(gRoot); 753 return ret; 754} 755 756/****************************************************************************** 757 * IOPMCopySleepWakeFailure 758 * 759 ******************************************************************************/ 760CFDictionaryRef IOPMCopySleepWakeFailure(void) 761{ 762 CFStringRef scFailureKey = NULL; 763 CFDictionaryRef scFailureDictionary = NULL; 764 SCDynamicStoreRef scDynStore = NULL; 765 766 scDynStore = SCDynamicStoreCreate(0, CFSTR("IOPMSleepFailure"), NULL, NULL); 767 if (!scDynStore) 768 goto exit; 769 770 scFailureKey = SCDynamicStoreKeyCreate( 771 kCFAllocatorDefault, 772 CFSTR("%@%@/%@"), 773 kSCDynamicStoreDomainState, 774 CFSTR("PowerManagement"), 775 CFSTR(kIOPMDynamicStoreSleepFailureKey)); 776 if (!scFailureKey) 777 goto exit; 778 779 scFailureDictionary = isA_CFDictionary(SCDynamicStoreCopyValue(scDynStore, scFailureKey)); 780 781exit: 782 if (scDynStore) 783 CFRelease(scDynStore); 784 if (scFailureKey) 785 CFRelease(scFailureKey); 786 return scFailureDictionary; 787} 788 789 790#define POWERD_XPC_ID "com.apple.iokit.powerdxpc" 791 792void IOPMClaimSystemWakeEvent( 793 CFStringRef identity, 794 CFStringRef reason, 795 CFDictionaryRef description) 796{ 797 xpc_connection_t connection = NULL; 798 xpc_object_t sendClaim = NULL; 799 xpc_object_t msg = NULL; 800 xpc_object_t desc = NULL; 801 char str[255]; 802 803 connection = xpc_connection_create_mach_service(POWERD_XPC_ID, 804 dispatch_get_global_queue(DISPATCH_QUEUE_CONCURRENT, 0), 0); 805 806 if (!connection) { 807 goto exit; 808 } 809 810 xpc_connection_set_target_queue(connection, 811 dispatch_get_global_queue(DISPATCH_QUEUE_CONCURRENT, 0)); 812 813 xpc_connection_set_event_handler(connection, 814 ^(xpc_object_t e __unused) { }); 815 816 sendClaim = xpc_dictionary_create(NULL, NULL, 0); 817 if (sendClaim) { 818 if (identity) { 819 CFStringGetCString(identity, str, sizeof(str), kCFStringEncodingUTF8); 820 xpc_dictionary_set_string(sendClaim, "identity", str); 821 } 822 if (reason) { 823 CFStringGetCString(reason, str, sizeof(str), kCFStringEncodingUTF8); 824 xpc_dictionary_set_string(sendClaim, "reason", str); 825 } 826 827 if (description) { 828 desc = _CFXPCCreateXPCObjectFromCFObject(description); 829 if (desc) { 830 xpc_dictionary_set_value(sendClaim, "description", desc); 831 xpc_release(desc); 832 } 833 } 834 } 835 836 msg = xpc_dictionary_create(NULL, NULL, 0); 837 if (msg) { 838 xpc_dictionary_set_value(msg, "claimSystemWakeEvent", sendClaim); 839 xpc_connection_resume(connection); 840 xpc_connection_send_message(connection, msg); 841 xpc_release(msg); 842 } 843exit: 844 if (connection) { 845 xpc_release(connection); 846 } 847} 848 849/*****************************************************************************/ 850/*****************************************************************************/ 851/*****************************************************************************/ 852/*****************************************************************************/ 853 854/* __IOPMConnection is the IOKit-tracking struct to keep track of 855 * open connections. 856 */ 857typedef struct { 858 uint32_t id; 859 int pid; 860 CFStringRef connectionName; 861 862 /* for dispatch-style notifications */ 863 mach_port_t mach_port; 864 dispatch_source_t dispatchDelivery; 865 866 /* for CFRunLoop-style notifications */ 867 CFMachPortRef localCFMachPort; 868 CFRunLoopSourceRef localCFMachPortRLS; 869 870 IOPMEventHandlerType userCallout; 871 void *userParam; 872 int runLoopCount; 873} __IOPMConnection; 874 875 876/*****************************************************************************/ 877/*****************************************************************************/ 878 879/* iopm_mach_port_callback 880 * The caller installed this callback on a runloop of their choice. 881 * Note that this code is running in the caller's runloop context; we don't have 882 * it serialized. 883 */ 884#define kMsgPayloadCount 2 885 886typedef struct { 887 mach_msg_header_t header; 888 mach_msg_body_t body; 889 uint32_t payload[kMsgPayloadCount]; 890} IOPMMessageStructure; 891 892static void iopm_mach_port_callback( 893 CFMachPortRef port __unused, 894 void *msg, 895 CFIndex size __unused, 896 void *info) 897{ 898 IOPMMessageStructure *m = (IOPMMessageStructure *)msg; 899 900 __IOPMConnection *connection = (__IOPMConnection *)info; 901 902 if (!connection || !connection->userCallout) { 903 return; 904 } 905 906 (*(connection->userCallout))( 907 connection->userParam, 908 (IOPMConnection)connection, 909 m->payload[1], // messageToken argument 910 m->payload[0]); // event DATA 911 912 return; 913} 914 915/*****************************************************************************/ 916/*****************************************************************************/ 917 918static kern_return_t _conveyMachPortToPowerd( 919 __IOPMConnection *connection, 920 mach_port_t the_port, 921 bool enable) 922{ 923 mach_port_t pm_server = MACH_PORT_NULL; 924 kern_return_t return_code = KERN_SUCCESS; 925 926 return_code = _pm_connect(&pm_server); 927 928 if(kIOReturnSuccess != return_code) { 929 goto exit; 930 } 931 932 return_code = io_pm_connection_schedule_notification(pm_server, connection->id, the_port, enable ? 0:1, &return_code); 933 934 _pm_disconnect(pm_server); 935 936exit: 937 return return_code; 938} 939 940 941/*****************************************************************************/ 942/*****************************************************************************/ 943#pragma mark - 944#pragma mark IOPMConnection 945 946IOReturn IOPMConnectionSetNotification( 947 IOPMConnection myConnection, 948 void *param, 949 IOPMEventHandlerType handler) 950{ 951 __IOPMConnection *connection = (__IOPMConnection *)myConnection; 952 953 if (!connection || !handler) 954 return kIOReturnBadArgument; 955 956 connection->userParam = param; 957 connection->userCallout = handler; 958 959 return kIOReturnSuccess; 960} 961 962/*****************************************************************************/ 963/*****************************************************************************/ 964 965IOReturn IOPMConnectionScheduleWithRunLoop( 966 IOPMConnection myConnection, 967 CFRunLoopRef theRunLoop, 968 CFStringRef runLoopMode) 969{ 970 __IOPMConnection *connection = (__IOPMConnection *)myConnection; 971 972 IOReturn return_code = kIOReturnError; 973 CFMachPortContext mpContext = { 1, (void *)connection, NULL, NULL, NULL }; 974 975 if (!connection || !theRunLoop || !runLoopMode) 976 return kIOReturnBadArgument; 977 978 if (NULL == connection->localCFMachPort) 979 { 980 // Create the mach port on which we'll receive mach messages 981 // from PM configd. 982 connection->localCFMachPort = CFMachPortCreate( 983 kCFAllocatorDefault, 984 iopm_mach_port_callback, 985 &mpContext, NULL); 986 987 if (connection->localCFMachPort) { 988 connection->localCFMachPortRLS = CFMachPortCreateRunLoopSource( 989 kCFAllocatorDefault, 990 connection->localCFMachPort, 991 0); 992 } 993 } 994 995 if (!connection->localCFMachPortRLS) 996 return kIOReturnInternalError; 997 998 // Record our new run loop. 999 connection->runLoopCount++; 1000 1001 CFRunLoopAddSource(theRunLoop, connection->localCFMachPortRLS, runLoopMode); 1002 1003 // We have a mapping of one mach_port connected to PM configd to as many 1004 // CFRunLoopSources that the caller originates. 1005 if (1 == connection->runLoopCount) 1006 { 1007 mach_port_t notify_mach_port = MACH_PORT_NULL; 1008 1009 if (connection->localCFMachPort) { 1010 notify_mach_port = CFMachPortGetPort(connection->localCFMachPort); 1011 } 1012 1013 return_code =_conveyMachPortToPowerd(connection, notify_mach_port, true); 1014 } 1015 1016 return return_code; 1017} 1018 1019/*****************************************************************************/ 1020/*****************************************************************************/ 1021 1022IOReturn IOPMConnectionUnscheduleFromRunLoop( 1023 IOPMConnection myConnection, 1024 CFRunLoopRef theRunLoop, 1025 CFStringRef runLoopMode) 1026{ 1027 __IOPMConnection *connection = (__IOPMConnection *)myConnection; 1028 IOReturn return_code = kIOReturnSuccess; 1029 1030 if (!connection || !theRunLoop || !runLoopMode) 1031 return kIOReturnBadArgument; 1032 1033 if (connection->localCFMachPort) { 1034 CFRunLoopRemoveSource(theRunLoop, connection->localCFMachPortRLS, runLoopMode); 1035 } 1036 1037 connection->runLoopCount--; 1038 1039 if (0 == connection->runLoopCount) 1040 { 1041 mach_port_t notify_mach_port = MACH_PORT_NULL; 1042 1043 if (connection->localCFMachPort) { 1044 notify_mach_port = CFMachPortGetPort(connection->localCFMachPort); 1045 } 1046 1047 return_code = _conveyMachPortToPowerd(connection, notify_mach_port, false); 1048 } 1049 1050 return return_code; 1051} 1052 1053/*****************************************************************************/ 1054/*****************************************************************************/ 1055 1056void IOPMConnectionSetDispatchQueue( 1057 IOPMConnection myConnection, 1058 dispatch_queue_t myQueue) 1059{ 1060 __IOPMConnection *connection = (__IOPMConnection *)myConnection; 1061 1062 if (!connection) 1063 return; 1064 1065 if (!myQueue) { 1066 /* Clean up a previously scheduled dispatch. */ 1067 if (connection->dispatchDelivery) 1068 { 1069 dispatch_source_cancel(connection->dispatchDelivery); 1070 } 1071 return; 1072 } 1073 1074 if (KERN_SUCCESS != mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &connection->mach_port)) 1075 { 1076 // Error allocating mach port 1077 return; 1078 } 1079 1080 mach_port_insert_right(mach_task_self(), connection->mach_port, connection->mach_port, 1081 MACH_MSG_TYPE_MAKE_SEND); 1082 1083 if (!(connection->dispatchDelivery 1084 = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, connection->mach_port, 0, myQueue))) 1085 { 1086 // Error creating dispatch_source 1087 mach_port_deallocate(mach_task_self(), connection->mach_port); 1088 mach_port_mod_refs(mach_task_self(), connection->mach_port, MACH_PORT_RIGHT_RECEIVE, -1); 1089 return; 1090 } 1091 1092 dispatch_source_set_cancel_handler(connection->dispatchDelivery, 1093 ^{ 1094 _conveyMachPortToPowerd(connection, connection->mach_port, false); 1095 1096 dispatch_release(connection->dispatchDelivery); 1097 connection->dispatchDelivery = 0; 1098 1099 mach_port_mod_refs(mach_task_self(), connection->mach_port, MACH_PORT_RIGHT_RECEIVE, -1); 1100 mach_port_deallocate(mach_task_self(), connection->mach_port); 1101 connection->mach_port = MACH_PORT_NULL; 1102 }); 1103 1104 dispatch_source_set_event_handler(connection->dispatchDelivery, 1105 ^{ 1106 struct { 1107 IOPMMessageStructure m; 1108 mach_msg_trailer_t trailer; 1109 } msg; 1110 1111 bzero(&msg, sizeof(msg)); 1112 kern_return_t status = mach_msg( ( void * )&msg, 1113 MACH_RCV_MSG | MACH_RCV_TIMEOUT, 1114 0, 1115 sizeof( msg ), 1116 connection->mach_port, 1117 0, 1118 MACH_PORT_NULL ); 1119 1120 if (!connection || !connection->userCallout 1121 || (KERN_SUCCESS != status)) 1122 { 1123 return; 1124 } 1125 1126 (*(connection->userCallout))(connection->userParam, 1127 (IOPMConnection)connection, 1128 msg.m.payload[1], msg.m.payload[0]); 1129 }); 1130 1131 dispatch_resume(connection->dispatchDelivery); 1132 1133 _conveyMachPortToPowerd(connection, connection->mach_port, true); 1134 1135 return; 1136} 1137 1138/*****************************************************************************/ 1139/*****************************************************************************/ 1140 1141IOReturn IOPMConnectionCreate( 1142 CFStringRef myName, 1143 IOPMCapabilityBits interests, 1144 IOPMConnection *newConnection) 1145{ 1146 __IOPMConnection *connection = NULL; 1147 1148 mach_port_t pm_server = MACH_PORT_NULL; 1149 int return_code = kIOReturnError; 1150 IOReturn err = kIOReturnError; 1151 kern_return_t kern_result = KERN_SUCCESS; 1152 1153 char arg_name_str[kMaxNameLength]; 1154 uint32_t new_connection_id = 0; 1155 1156 // * vet argument newConnection 1157 // * and create new connection 1158 if (!newConnection) 1159 return kIOReturnBadArgument; 1160 1161 *newConnection = NULL; 1162 1163 err = _pm_connect(&pm_server); 1164 if(kIOReturnSuccess != err) { 1165 return_code = kIOReturnInternalError; 1166 goto exit; 1167 } 1168 1169 // * vet argument 'interests' 1170 // A caller specifying 0 interests would get no notifications 1171 if (0 == interests) { 1172 return_code = kIOReturnBadArgument; 1173 goto exit; 1174 } 1175 1176 // * vet argument 'myName' 1177 if (!myName || (kMaxNameLength < CFStringGetLength(myName))) { 1178 return_code = kIOReturnBadArgument; 1179 goto exit; 1180 } 1181 CFStringGetCString( myName, arg_name_str, 1182 sizeof(arg_name_str), kCFStringEncodingMacRoman); 1183 1184 1185 connection = calloc(1, sizeof(__IOPMConnection)); 1186 if (!connection) { 1187 return_code = kIOReturnInternalError; 1188 goto exit; 1189 } 1190 1191 kern_result = io_pm_connection_create( 1192 pm_server, 1193 mach_task_self(), 1194 arg_name_str, 1195 interests, 1196 &new_connection_id, 1197 &return_code); 1198 1199 if (KERN_SUCCESS != kern_result) { 1200 return_code = kern_result; 1201 goto exit; 1202 } 1203 1204 connection->id = (int)new_connection_id; 1205 *newConnection = (void *)connection; 1206 1207 return_code = kIOReturnSuccess; 1208 1209exit: 1210 if (MACH_PORT_NULL != pm_server) { 1211 _pm_disconnect(pm_server); 1212 } 1213 1214 return return_code; 1215 1216} 1217 1218/*****************************************************************************/ 1219/*****************************************************************************/ 1220 1221IOReturn IOPMConnectionRelease(IOPMConnection connection) 1222{ 1223 __IOPMConnection *connection_private = (__IOPMConnection *)connection; 1224 IOReturn return_code = kIOReturnError; 1225 mach_port_t pm_server = MACH_PORT_NULL; 1226 kern_return_t kern_result; 1227 IOReturn err; 1228 1229 err = _pm_connect(&pm_server); 1230 if(kIOReturnSuccess != err) { 1231 return_code = kIOReturnInternalError; 1232 goto exit; 1233 } 1234 1235#if !TARGET_OS_IPHONE 1236 if (connection_private->dispatchDelivery) { 1237 IOPMConnectionSetDispatchQueue(connection, NULL); 1238 } 1239#endif 1240 1241 kern_result = io_pm_connection_release(pm_server, 1242 connection_private->id, 1243 &return_code); 1244 if (kern_result != KERN_SUCCESS) { 1245 return_code = kern_result; 1246 } 1247exit: 1248 if (MACH_PORT_NULL != pm_server) { 1249 _pm_disconnect(pm_server); 1250 } 1251 1252 return return_code; 1253} 1254 1255/*****************************************************************************/ 1256/*****************************************************************************/ 1257 1258IOReturn IOPMConnectionAcknowledgeEvent( 1259 IOPMConnection connect, 1260 IOPMConnectionMessageToken token) 1261{ 1262#if TARGET_OS_IPHONE 1263 (void)connect; 1264 (void)token; 1265 1266 return kIOReturnUnsupported; 1267#else 1268 return IOPMConnectionAcknowledgeEventWithOptions( 1269 connect, token, NULL); 1270#endif /* TARGET_OS_IPHONE */ 1271} 1272 1273 1274/*****************************************************************************/ 1275/*****************************************************************************/ 1276 1277IOReturn IOPMConnectionAcknowledgeEventWithOptions( 1278 IOPMConnection myConnection, 1279 IOPMConnectionMessageToken token, 1280 CFDictionaryRef options) 1281{ 1282#if TARGET_OS_IPHONE 1283 (void)myConnection; 1284 (void)token; 1285 (void)options; 1286 1287 return kIOReturnUnsupported; 1288#else 1289 __IOPMConnection *connection = (__IOPMConnection *)myConnection; 1290 1291 IOReturn return_code = kIOReturnError; 1292 mach_port_t pm_server = MACH_PORT_NULL; 1293 kern_return_t kern_result; 1294 IOReturn err; 1295 1296 CFDataRef serializedData = NULL; 1297 vm_offset_t buffer_ptr = 0; 1298 size_t buffer_size = 0; 1299 1300 // No response is expected when token is 0 1301 if (token == 0) 1302 return kIOReturnSuccess; 1303 1304 err = _pm_connect(&pm_server); 1305 if(kIOReturnSuccess != err) { 1306 return_code = kIOReturnInternalError; 1307 goto exit; 1308 } 1309 1310 if (options) 1311 { 1312 serializedData = CFPropertyListCreateData( 1313 kCFAllocatorDefault, 1314 (CFPropertyListRef)options, 1315 kCFPropertyListBinaryFormat_v1_0, 0, NULL); 1316 1317 if (serializedData) 1318 { 1319 buffer_ptr = (vm_offset_t)CFDataGetBytePtr(serializedData); 1320 buffer_size = (size_t)CFDataGetLength(serializedData); 1321 1322 } 1323 } 1324 1325 kern_result = io_pm_connection_acknowledge_event(pm_server, 1326 (uint32_t)connection->id, 1327 (uint32_t)token, 1328 buffer_ptr, 1329 buffer_size, 1330 &return_code); 1331 1332 if (kern_result != KERN_SUCCESS) { 1333 return_code = kern_result; 1334 } 1335exit: 1336 if (MACH_PORT_NULL != pm_server) { 1337 _pm_disconnect(pm_server); 1338 } 1339 1340 if (serializedData) CFRelease(serializedData); 1341 1342 return return_code; 1343#endif /* TARGET_OS_IPHONE */ 1344} 1345 1346/*****************************************************************************/ 1347/*****************************************************************************/ 1348 1349IOReturn IOPMCopyConnectionStatus(int statusSelector, CFTypeRef *output) 1350{ 1351 int return_code = kIOReturnError; 1352 mach_port_t pm_server = MACH_PORT_NULL; 1353 kern_return_t kern_result; 1354 IOReturn err; 1355 1356 vm_offset_t buffer_ptr = 0; 1357 mach_msg_type_number_t buffer_size = 0; 1358 1359 CFDictionaryRef *dictionaryOutput = (CFDictionaryRef *)output; 1360 1361 err = _pm_connect(&pm_server); 1362 if(kIOReturnSuccess != err) { 1363 return_code = kIOReturnInternalError; 1364 goto exit; 1365 } 1366 1367 // TODO: serialize passed-in options into buffer_ptr & buffer_size 1368 *dictionaryOutput = NULL; 1369 1370 1371 kern_result = io_pm_connection_copy_status(pm_server, 1372 (uint32_t)statusSelector, 1373 &buffer_ptr, 1374 &buffer_size, 1375 &return_code); 1376 1377 if (kern_result != KERN_SUCCESS) { 1378 return_code = kern_result; 1379 } 1380exit: 1381 if (MACH_PORT_NULL != pm_server) { 1382 _pm_disconnect(pm_server); 1383 } 1384 1385 return return_code; 1386} 1387 1388/*****************************************************************************/ 1389/*****************************************************************************/ 1390 1391#define SYSTEM_ON_CAPABILITIES (kIOPMCapabilityCPU | kIOPMCapabilityVideo | kIOPMCapabilityAudio \ 1392 | kIOPMCapabilityNetwork | kIOPMCapabilityDisk) 1393 1394IOPMCapabilityBits IOPMConnectionGetSystemCapabilities(void) 1395{ 1396 1397 mach_port_t pm_server = MACH_PORT_NULL; 1398 kern_return_t kern_result; 1399 IOPMCapabilityBits ret_cap = SYSTEM_ON_CAPABILITIES; 1400 IOReturn return_code = kIOReturnError; 1401 1402 return_code = _pm_connect(&pm_server); 1403 1404 if(pm_server == MACH_PORT_NULL) 1405 return ret_cap; 1406 1407 kern_result = io_pm_get_capability_bits(pm_server, &ret_cap, &return_code); 1408 1409 _pm_disconnect(pm_server); 1410 1411 return ret_cap; 1412 1413 1414} 1415 1416 1417bool IOPMIsADarkWake(IOPMCapabilityBits c) 1418{ 1419 return ((c & kIOPMCapabilityCPU) && !(c & kIOPMCapabilityVideo)); 1420} 1421 1422bool IOPMAllowsBackgroundTask(IOPMCapabilityBits c) 1423{ 1424 return (0 != (c & kIOPMCapabilityBackgroundTask)); 1425} 1426 1427bool IOPMAllowsPushServiceTask(IOPMCapabilityBits c) 1428{ 1429 return (0 != (c & kIOPMCapabilityPushServiceTask)); 1430} 1431 1432bool IOPMIsASilentWake(IOPMCapabilityBits c) 1433{ 1434 return (0 != (c & kIOPMCapabilitySilentRunning)); 1435} 1436 1437bool IOPMIsAUserWake(IOPMCapabilityBits c) 1438{ 1439 return (0 != (c & kIOPMCapabilityVideo)); 1440} 1441 1442bool IOPMIsASleep(IOPMCapabilityBits c) 1443{ 1444 return (0 == (c & kIOPMCapabilityCPU)); 1445} 1446 1447bool IOPMGetCapabilitiesDescription(char *buf, int buf_size, IOPMCapabilityBits in_caps) 1448{ 1449 uint64_t caps = (uint64_t)in_caps; 1450 int printed_total = 0; 1451 char *on_sleep_dark = ""; 1452 1453 if (IOPMIsASleep(caps)) 1454 { 1455 on_sleep_dark = "Sleep"; 1456 } else if (IOPMIsADarkWake(caps)) 1457 { 1458 on_sleep_dark = "DarkWake"; 1459 } else if (IOPMIsAUserWake(caps)) 1460 { 1461 on_sleep_dark = "FullWake"; 1462 } else 1463 { 1464 on_sleep_dark = "Unknown"; 1465 } 1466 1467 printed_total = snprintf(buf, buf_size, "%s:%s%s%s%s%s%s%s", 1468 on_sleep_dark, 1469 (caps & kIOPMCapabilityCPU) ? "cpu ":"<off> ", 1470 (caps & kIOPMCapabilityDisk) ? "disk ":"", 1471 (caps & kIOPMCapabilityNetwork) ? "net ":"", 1472 (caps & kIOPMCapabilityAudio) ? "aud ":"", 1473 (caps & kIOPMCapabilityVideo) ? "vid ":"", 1474 (caps & kIOPMCapabilityPushServiceTask) ? "push ":"", 1475 (caps & kIOPMCapabilityBackgroundTask) ? "bg ":""); 1476 1477 return (printed_total <= buf_size); 1478} 1479 1480 1481/*****************************************************************************/ 1482/*****************************************************************************/ 1483#pragma mark - 1484#pragma mark Talking about DarkWake 1485 1486bool IOPMGetSleepServicesActive(void) 1487{ 1488 int token = 0; 1489 uint64_t payload = 0; 1490 1491 if (NOTIFY_STATUS_OK == notify_register_check(kIOPMSleepServiceActiveNotifyName, &token)) 1492 { 1493 notify_get_state(token, &payload); 1494 notify_cancel(token); 1495 } 1496 1497 return ((payload & kIOPMSleepServiceActiveNotifyBit) ? true : false); 1498} 1499 1500 1501int IOPMGetDarkWakeThermalEmergencyCount(void) 1502{ 1503 return IOPMGetValueInt(kIOPMDarkWakeThermalEventCount); 1504} 1505 1506/*****************************************************************************/ 1507/*****************************************************************************/ 1508#pragma mark - 1509#pragma mark Power Internals 1510 1511/*! 1512 * @function IOPMGetValueInt 1513 * @abstract For IOKit use only. 1514 */ 1515int IOPMGetValueInt(int selector) { 1516 mach_port_t pm_server = MACH_PORT_NULL; 1517 int valint = 0; 1518 kern_return_t kern_result; 1519 1520 if (kIOReturnSuccess == _pm_connect(&pm_server)) 1521 { 1522 kern_result = io_pm_get_value_int( 1523 pm_server, 1524 selector, 1525 &valint); 1526 if (KERN_SUCCESS != kern_result) { 1527 valint = 0; 1528 } 1529 _pm_disconnect(pm_server); 1530 } 1531 return valint; 1532} 1533 1534/*! 1535 * @function IOPMSetValueInt 1536 * @abstract For IOKit use only. 1537 */ 1538void IOPMSetValueInt(int selector, int value) { 1539 mach_port_t pm_server = MACH_PORT_NULL; 1540 int rc = kIOReturnSuccess; 1541 1542 if (kIOReturnSuccess == _pm_connect(&pm_server)) 1543 { 1544 io_pm_set_value_int( 1545 pm_server, 1546 selector, 1547 value, &rc); 1548 _pm_disconnect(pm_server); 1549 } 1550 return; 1551} 1552 1553 1554IOReturn IOPMSetDebugFlags(uint32_t newFlags, uint32_t *oldFlags) 1555{ 1556 1557 mach_port_t pm_server = MACH_PORT_NULL; 1558 kern_return_t kern_result; 1559 uint32_t flags; 1560 IOReturn return_code = kIOReturnError; 1561 1562 return_code = _pm_connect(&pm_server); 1563 1564 if(pm_server == MACH_PORT_NULL) 1565 return kIOReturnNotReady; 1566 1567 kern_result = io_pm_set_debug_flags(pm_server, newFlags, kIOPMDebugFlagsSetValue, &flags, &return_code); 1568 1569 _pm_disconnect(pm_server); 1570 1571 if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) { 1572 if (oldFlags) 1573 *oldFlags = flags; 1574 return kIOReturnSuccess; 1575 } 1576 else 1577 return return_code; 1578} 1579 1580#if TARGET_OS_IPHONE 1581IOReturn IOPMSetBTWakeInterval(uint32_t newInterval __unused, 1582 uint32_t *oldInterval __unused) 1583{ 1584#else 1585IOReturn IOPMSetBTWakeInterval(uint32_t newInterval, uint32_t *oldInterval) 1586{ 1587 1588 mach_port_t pm_server = MACH_PORT_NULL; 1589 kern_return_t kern_result; 1590 uint32_t interval = 0; 1591 IOReturn return_code = kIOReturnError; 1592 1593 return_code = _pm_connect(&pm_server); 1594 1595 if(pm_server == MACH_PORT_NULL) 1596 return kIOReturnNotReady; 1597 1598 kern_result = io_pm_set_bt_wake_interval(pm_server, newInterval, &interval, &return_code); 1599 1600 _pm_disconnect(pm_server); 1601 1602 if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) { 1603 if (oldInterval) 1604 *oldInterval = interval; 1605 return kIOReturnSuccess; 1606 } 1607 else 1608 return return_code; 1609 1610#endif 1611 return kIOReturnSuccess; 1612 1613} 1614 1615#if TARGET_OS_IPHONE 1616IOReturn IOPMSetDWLingerInterval(uint32_t newInterval __unused, 1617 uint32_t *oldInterval __unused) 1618{ 1619#else 1620IOReturn IOPMSetDWLingerInterval(uint32_t newInterval, uint32_t *oldInterval) 1621{ 1622 1623 mach_port_t pm_server = MACH_PORT_NULL; 1624 kern_return_t kern_result; 1625 uint32_t interval = 0; 1626 IOReturn return_code = kIOReturnError; 1627 1628 return_code = _pm_connect(&pm_server); 1629 1630 if(pm_server == MACH_PORT_NULL) 1631 return kIOReturnNotReady; 1632 1633 kern_result = io_pm_set_dw_linger_interval(pm_server, newInterval, &interval, &return_code); 1634 1635 _pm_disconnect(pm_server); 1636 1637 if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) { 1638 if (oldInterval) 1639 *oldInterval = interval; 1640 return kIOReturnSuccess; 1641 } 1642 else 1643 return return_code; 1644 1645#endif 1646 return kIOReturnSuccess; 1647 1648} 1649 1650IOReturn IOPMChangeSystemActivityAssertionBehavior(uint32_t newFlags, uint32_t *oldFlags) 1651{ 1652 mach_port_t pm_server = MACH_PORT_NULL; 1653 kern_return_t kern_result; 1654 uint32_t flags = 0; 1655 IOReturn return_code = kIOReturnError; 1656 1657 return_code = _pm_connect(&pm_server); 1658 1659 if(pm_server == MACH_PORT_NULL) 1660 return kIOReturnNotReady; 1661 1662 kern_result = io_pm_change_sa_assertion_behavior(pm_server, newFlags, &flags, &return_code); 1663 1664 _pm_disconnect(pm_server); 1665 1666 if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) 1667 { 1668 if(flags) 1669 *oldFlags = flags; 1670 return kIOReturnSuccess; 1671 } 1672 else 1673 return return_code; 1674} 1675 1676/*****************************************************************************/ 1677/*****************************************************************************/ 1678IOReturn IOPMCtlAssertionType(char *type, int op) 1679{ 1680 mach_port_t pm_server = MACH_PORT_NULL; 1681 kern_return_t kern_result; 1682 IOReturn return_code = kIOReturnError; 1683 1684 return_code = _pm_connect(&pm_server); 1685 1686 if(pm_server == MACH_PORT_NULL) 1687 return kIOReturnNotReady; 1688 1689 kern_result = io_pm_ctl_assertion_type(pm_server, type, 1690 op, &return_code); 1691 1692 _pm_disconnect(pm_server); 1693 1694 if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) { 1695 return kIOReturnSuccess; 1696 } 1697 else 1698 return return_code; 1699} 1700 1701/*****************************************************************************/ 1702/*****************************************************************************/ 1703#define kPMReportPowerOn 0x01 1704#define kPMReportDeviceUsable 0x02 1705#define kPMReportLowPower 0x04 1706CFDictionaryRef IOPMCopyPowerStateInfo(uint64_t state_id) 1707{ 1708 CFMutableDictionaryRef dict = NULL; 1709 CFTypeRef objRef = NULL; 1710 uint32_t val = 0; 1711 1712 dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1713 0, 1714 &kCFTypeDictionaryKeyCallBacks, 1715 &kCFTypeDictionaryValueCallBacks); 1716 1717 if (!dict) 1718 return kIOReturnNoMemory; 1719 1720 val = state_id & 0xf; 1721 objRef = CFNumberCreate(0, kCFNumberIntType, &val); 1722 if (objRef) { 1723 CFDictionarySetValue(dict, kIOPMNodeCurrentState, objRef); 1724 CFRelease(objRef); 1725 } 1726 1727 val = ((state_id >> 4) & 0xf); 1728 objRef = CFNumberCreate(0, kCFNumberIntType, &val); 1729 if (objRef) { 1730 CFDictionarySetValue(dict, kIOPMNodeMaxState, objRef); 1731 CFRelease(objRef); objRef = NULL; 1732 } 1733 1734 if ( (state_id >> 8) & kPMReportPowerOn) 1735 CFDictionarySetValue(dict, kIOPMNodeIsPowerOn, kCFBooleanTrue); 1736 else 1737 CFDictionarySetValue(dict, kIOPMNodeIsPowerOn, kCFBooleanFalse); 1738 1739 if ( (state_id >> 8) & kPMReportDeviceUsable) 1740 CFDictionarySetValue(dict, kIOPMNodeIsDeviceUsable, kCFBooleanTrue); 1741 else 1742 CFDictionarySetValue(dict, kIOPMNodeIsDeviceUsable, kCFBooleanFalse); 1743 1744 1745 if ( (state_id >> 8) & kPMReportLowPower) 1746 CFDictionarySetValue(dict, kIOPMNodeIsLowPower, kCFBooleanTrue); 1747 else 1748 CFDictionarySetValue(dict, kIOPMNodeIsLowPower, kCFBooleanFalse); 1749 1750 return dict; 1751} 1752/*****************************************************************************/ 1753/*****************************************************************************/ 1754 1755IOReturn IOPMAssertionNotify(char *name, int req_type) 1756{ 1757 mach_port_t pm_server = MACH_PORT_NULL; 1758 kern_return_t kern_result; 1759 IOReturn return_code = kIOReturnError; 1760 1761 return_code = _pm_connect(&pm_server); 1762 1763 if(pm_server == MACH_PORT_NULL) 1764 return kIOReturnNotReady; 1765 1766 kern_result = io_pm_assertion_notify(pm_server, name, 1767 req_type, &return_code); 1768 1769 _pm_disconnect(pm_server); 1770 1771 if ( kern_result == KERN_SUCCESS && return_code == kIOReturnSuccess) { 1772 return kIOReturnSuccess; 1773 } 1774 else 1775 return return_code; 1776} 1777 1778/*****************************************************************************/ 1779 1780#if 0 1781bool IOPMSystemPowerStateSupportsAcknowledgementOption( 1782 IOPMCapabilityBits stateDescriptor, 1783 CFStringRef acknowledgementOption) 1784{ 1785 if (!acknowledgementOption) 1786 return false; 1787 1788 if ( 0 != (stateDescriptor & kIOPMSytemPowerStateCapabilitiesMask) ) 1789 { 1790 // The flags date & requiredcapabilities are only valid on going to sleep transitions 1791 return false; 1792 } 1793 1794 if (CFEqual(acknowledgementOption, kIOPMAcknowledgmentOptionSystemCapabilityRequirements) 1795 || CFEqual(acknowledgementOption, kIOPMAcknowledgmentOptionWakeDate)) 1796 { 1797 return true; 1798 } 1799 1800 return false; 1801} 1802#endif 1803