1/* 2 * Copyright (c) 2010 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/CFPriv.h> 26#include <mach/mach.h> 27#include <IOKit/pwr_mgt/IOPMLib.h> 28#include <IOKit/pwr_mgt/IOPMLibPrivate.h> 29#include "IOSystemConfiguration.h" 30#include <sys/time.h> 31#include <notify.h> 32#include <execinfo.h> 33#include <asl.h> 34 35#include "powermanagement_mig.h" 36#include "powermanagement.h" 37 38#include <servers/bootstrap.h> 39 40 41#define kAssertionsArraySize 5 42#define NUM_BT_FRAMES 8 43 44static uint64_t collectBackTrace = 0; 45 46IOReturn _pm_connect(mach_port_t *newConnection); 47IOReturn _pm_disconnect(mach_port_t connection); 48__private_extern__ IOReturn _copyPMServerObject(int selector, int assertionID, CFTypeRef *objectOut); 49__private_extern__ io_registry_entry_t getPMRootDomainRef(void); 50 51static IOReturn pm_connect_init(mach_port_t *newConnection) 52{ 53#if __i386__ || __x86_64__ 54 static int disableAppSleepToken = 0; 55 static int enableAppSleepToken = 0; 56#endif 57 static int collectBackTraceToken = 0; 58 59#if !TARGET_OS_IPHONE 60 if ( !disableAppSleepToken ) { 61 char notify_str[128]; 62 63 snprintf(notify_str, sizeof(notify_str), "%s.%d", 64 kIOPMDisableAppSleepPrefix, getpid()); 65 66 notify_register_dispatch( 67 notify_str, 68 &disableAppSleepToken, 69 dispatch_get_main_queue(), 70 ^(int t __unused){ 71 __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion, 72 CFSTR("App is holding power assertion.")); 73 }); 74 } 75 76 if ( !enableAppSleepToken ) { 77 char notify_str[128]; 78 79 snprintf(notify_str, sizeof(notify_str), "%s.%d", 80 kIOPMEnableAppSleepPrefix, getpid()); 81 82 notify_register_dispatch( 83 notify_str, 84 &enableAppSleepToken, 85 dispatch_get_main_queue(), 86 ^(int t __unused){ 87 __CFRunLoopSetOptionsReason(__CFRunLoopOptionsDropAssertion, 88 CFSTR("App released all power assertions.")); 89 }); 90 } 91#endif 92 93 if (!collectBackTraceToken) { 94 notify_register_dispatch( 95 kIOPMAssertionsCollectBTString, 96 &collectBackTraceToken, 97 dispatch_get_main_queue(), 98 ^(int t){ 99 notify_get_state(t, &collectBackTrace); 100 }); 101 notify_get_state(collectBackTraceToken, &collectBackTrace); 102 103 } 104 105 return _pm_connect(newConnection); 106} 107 108static IOReturn pm_connect_close(mach_port_t connection) 109{ 110 return _pm_disconnect(connection); 111} 112 113static inline void saveBackTrace(CFMutableDictionaryRef props) 114{ 115 116 void * bt[NUM_BT_FRAMES]; 117 size_t btsize = 0; 118 char **syms = NULL; 119 int i; 120 CFStringRef frame_cf = NULL; 121 CFMutableArrayRef syms_cf = NULL; 122 123 124 int nframes = backtrace((void**)(&bt), NUM_BT_FRAMES); 125 btsize = nframes * sizeof(bt[0]); 126 127 syms = backtrace_symbols(bt, nframes); 128 syms_cf = CFArrayCreateMutable(0, nframes, &kCFTypeArrayCallBacks); 129 if (syms && syms_cf) { 130 for (i = 0; i < nframes; i++) { 131 frame_cf = NULL; 132 frame_cf = CFStringCreateWithCString(NULL, syms[i], 133 kCFStringEncodingMacRoman); 134 if (frame_cf) { 135 CFArrayInsertValueAtIndex(syms_cf, i, frame_cf); 136 CFRelease(frame_cf); 137 } 138 else { 139 CFArrayInsertValueAtIndex(syms_cf, i, CFSTR(" ")); 140 } 141 } 142 CFDictionarySetValue(props, kIOPMAssertionCreatorBacktrace, syms_cf); 143 } 144 145 if (syms_cf) CFRelease(syms_cf); 146 if (syms) free(syms); 147} 148 149 150 151/****************************************************************************** 152 * IOPMAssertionCreate 153 * 154 * Deprecated but still supported wrapper for IOPMAssertionCreateWithProperties 155 ******************************************************************************/ 156IOReturn IOPMAssertionCreate( 157 CFStringRef AssertionType, 158 IOPMAssertionLevel AssertionLevel, 159 IOPMAssertionID *AssertionID) 160{ 161 return IOPMAssertionCreateWithName(AssertionType, AssertionLevel, 162 CFSTR("Nameless (via IOPMAssertionCreate)"), AssertionID); 163} 164 165/****************************************************************************** 166 * IOPMAssertionCreateWithName 167 * 168 * Deprecated but still supported wrapper for IOPMAssertionCreateWithProperties 169 ******************************************************************************/ 170IOReturn IOPMAssertionCreateWithName( 171 CFStringRef AssertionType, 172 IOPMAssertionLevel AssertionLevel __unused, 173 CFStringRef AssertionName, 174 IOPMAssertionID *AssertionID) 175{ 176 CFMutableDictionaryRef properties = NULL; 177 IOReturn result = kIOReturnError; 178 179 if (!AssertionName || !AssertionID || !AssertionType) 180 return kIOReturnBadArgument; 181 182 properties = CFDictionaryCreateMutable(0, 3, &kCFTypeDictionaryKeyCallBacks, 183 &kCFTypeDictionaryValueCallBacks); 184 185 if (properties) 186 { 187 188 CFDictionarySetValue(properties, kIOPMAssertionTypeKey, AssertionType); 189 190 CFDictionarySetValue(properties, kIOPMAssertionNameKey, AssertionName); 191 192 CFDictionarySetValue(properties, kIOPMAssertionUsedDeprecatedCreateAPIKey, kCFBooleanTrue); 193 194 result = IOPMAssertionCreateWithProperties(properties, AssertionID); 195 196 CFRelease(properties); 197 } 198 199 return result; 200} 201 202/****************************************************************************** 203 * IOPMAssertionCreateWithDescription 204 * 205 ******************************************************************************/ 206 207IOReturn IOPMAssertionCreateWithDescription( 208 CFStringRef AssertionType, 209 CFStringRef Name, 210 CFStringRef Details, 211 CFStringRef HumanReadableReason, 212 CFStringRef LocalizationBundlePath, 213 CFTimeInterval Timeout, 214 CFStringRef TimeoutAction, 215 IOPMAssertionID *AssertionID) 216{ 217 CFMutableDictionaryRef descriptor = NULL; 218 IOReturn ret = kIOReturnError; 219 220 if (!AssertionType || !Name || !AssertionID) { 221 ret = kIOReturnBadArgument; 222 goto exit; 223 } 224 225 descriptor = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 226 if (!descriptor) { 227 goto exit; 228 } 229 230 CFDictionarySetValue(descriptor, kIOPMAssertionNameKey, Name); 231 232 CFDictionarySetValue(descriptor, kIOPMAssertionTypeKey, AssertionType); 233 234 if (Details) { 235 CFDictionarySetValue(descriptor, kIOPMAssertionDetailsKey, Details); 236 } 237 if (HumanReadableReason) { 238 CFDictionarySetValue(descriptor, kIOPMAssertionHumanReadableReasonKey, HumanReadableReason); 239 } 240 if (LocalizationBundlePath) { 241 CFDictionarySetValue(descriptor, kIOPMAssertionLocalizationBundlePathKey, LocalizationBundlePath); 242 } 243 if (Timeout) { 244 CFNumberRef Timeout_num = CFNumberCreate(0, kCFNumberDoubleType, &Timeout); 245 CFDictionarySetValue(descriptor, kIOPMAssertionTimeoutKey, Timeout_num); 246 CFRelease(Timeout_num); 247 } 248 if (TimeoutAction) { 249 CFDictionarySetValue(descriptor, kIOPMAssertionTimeoutActionKey, TimeoutAction); 250 } 251 252 ret = IOPMAssertionCreateWithProperties(descriptor, AssertionID); 253 254 CFRelease(descriptor); 255 256exit: 257 return ret; 258} 259 260/****************************************************************************** 261 * IOPMAssertionCreateWithProperties 262 * 263 ******************************************************************************/ 264IOReturn IOPMAssertionCreateWithProperties( 265 CFDictionaryRef AssertionProperties, 266 IOPMAssertionID *AssertionID) 267{ 268 IOReturn return_code = kIOReturnError; 269 kern_return_t kern_result = KERN_SUCCESS; 270 mach_port_t pm_server = MACH_PORT_NULL; 271 IOReturn err; 272 CFDataRef flattenedProps = NULL; 273 CFStringRef assertionTypeString = NULL; 274 CFMutableDictionaryRef mutableProps = NULL; 275 int disableAppSleep = 0; 276#if TARGET_OS_IPHONE 277 static int resyncToken = 0; 278 static CFMutableDictionaryRef resyncCopy = NULL; 279#endif 280 281 if (!AssertionProperties || !AssertionID) { 282 return_code = kIOReturnBadArgument; 283 goto exit; 284 } 285 286 err = pm_connect_init(&pm_server); 287 if(kIOReturnSuccess != err) { 288 return_code = kIOReturnInternalError; 289 goto exit; 290 } 291 292 293 assertionTypeString = CFDictionaryGetValue(AssertionProperties, kIOPMAssertionTypeKey); 294 295 296#if TARGET_OS_IPHONE 297 298 if (isA_CFString(assertionTypeString) && 299 CFEqual(assertionTypeString, kIOPMAssertionTypeEnableIdleSleep) && !resyncToken) { 300 301 resyncCopy = CFDictionaryCreateMutableCopy(NULL, 0, AssertionProperties); 302 notify_register_dispatch( kIOUserAssertionReSync, 303 &resyncToken, dispatch_get_main_queue(), 304 ^(int t __unused) { 305 IOPMAssertionID id; 306 IOPMAssertionCreateWithProperties(resyncCopy, &id); 307 }); 308 } 309#endif 310 311 if (collectBackTrace) { 312 if (!mutableProps) { 313 mutableProps = CFDictionaryCreateMutableCopy(NULL, 0, AssertionProperties); 314 if (!mutableProps) { 315 return_code = kIOReturnInternalError; 316 goto exit; 317 } 318 } 319 saveBackTrace(mutableProps); 320 } 321 322 flattenedProps = CFPropertyListCreateData(0, (mutableProps != NULL) ? mutableProps : AssertionProperties, 323 kCFPropertyListBinaryFormat_v1_0, 0, NULL /* error */); 324 if (!flattenedProps) { 325 return_code = kIOReturnBadArgument; 326 goto exit; 327 } 328 329 330 kern_result = io_pm_assertion_create( pm_server, 331 (vm_offset_t)CFDataGetBytePtr(flattenedProps), 332 CFDataGetLength(flattenedProps), 333 (int *)AssertionID, 334 &disableAppSleep, 335 &return_code); 336 337 if(KERN_SUCCESS != kern_result) { 338 return_code = kIOReturnInternalError; 339 } 340#if !TARGET_OS_IPHONE 341 else if (disableAppSleep) { 342 CFStringRef assertionName = NULL; 343 CFStringRef appSleepString = NULL; 344 345 assertionName = CFDictionaryGetValue(AssertionProperties, kIOPMAssertionNameKey); 346 appSleepString = CFStringCreateWithFormat(NULL, NULL, 347 CFSTR("App is holding power assertion %u with name \'%@\' "), 348 *AssertionID, assertionName); 349 350 __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion, appSleepString); 351 352 CFRelease(appSleepString); 353 } 354#endif 355 356exit: 357 if (flattenedProps) { 358 CFRelease(flattenedProps); 359 } 360 361 if (MACH_PORT_NULL != pm_server) { 362 pm_connect_close(pm_server); 363 } 364 365 // Release mutableProps if allocated in this function 366 if (mutableProps) 367 CFRelease(mutableProps); 368 369 return return_code; 370} 371 372/****************************************************************************** 373 * IOPMPerformBlockWithAssertion 374 * 375 ******************************************************************************/ 376IOReturn IOPMPerformBlockWithAssertion( 377 CFDictionaryRef assertion_properties, 378 dispatch_block_t the_block) 379{ 380 IOPMAssertionID _id = kIOPMNullAssertionID; 381 382 if (!assertion_properties || !the_block) { 383 return kIOReturnBadArgument; 384 } 385 386 IOPMAssertionCreateWithProperties(assertion_properties, _id); 387 388 the_block(); 389 390 if (kIOPMNullAssertionID != _id) { 391 IOPMAssertionRelease(_id); 392 } 393 394 return kIOReturnSuccess; 395} 396 397/****************************************************************************** 398 * IOPMAssertionsRetain 399 * 400 ******************************************************************************/ 401void IOPMAssertionRetain(IOPMAssertionID theAssertion) 402{ 403 IOReturn return_code = kIOReturnError; 404 kern_return_t kern_result = KERN_SUCCESS; 405 mach_port_t pm_server = MACH_PORT_NULL; 406 IOReturn err; 407 int disableAppSleep = 0; 408 int enableAppSleep = 0; 409 410 if (!theAssertion) { 411 return_code = kIOReturnBadArgument; 412 goto exit; 413 } 414 415 err = pm_connect_init(&pm_server); 416 if(kIOReturnSuccess != err) { 417 return_code = kIOReturnInternalError; 418 goto exit; 419 } 420 421 kern_result = io_pm_assertion_retain_release( pm_server, 422 (int)theAssertion, 423 kIOPMAssertionMIGDoRetain, 424 &disableAppSleep, 425 &enableAppSleep, 426 &return_code); 427 428 if(KERN_SUCCESS != kern_result) { 429 return_code = kIOReturnInternalError; 430 } 431#if !TARGET_OS_IPHONE 432 else if (disableAppSleep) { 433 CFStringRef appSleepString = NULL; 434 435 appSleepString = CFStringCreateWithFormat(NULL, NULL, CFSTR("App is holding power assertion %u"), 436 theAssertion); 437 __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion, appSleepString); 438 439 CFRelease(appSleepString); 440 } 441#endif 442 443 444exit: 445 if (MACH_PORT_NULL != pm_server) { 446 pm_connect_close(pm_server); 447 } 448 return; 449} 450 451 452/****************************************************************************** 453 * IOPMAssertionsRelease 454 * 455 ******************************************************************************/ 456IOReturn IOPMAssertionRelease(IOPMAssertionID AssertionID) 457{ 458 IOReturn return_code = kIOReturnError; 459 kern_return_t kern_result = KERN_SUCCESS; 460 mach_port_t pm_server = MACH_PORT_NULL; 461 IOReturn err; 462 int disableAppSleep = 0; 463 int enableAppSleep = 0; 464 465 if (!AssertionID) { 466 return_code = kIOReturnBadArgument; 467 goto exit; 468 } 469 470 err = pm_connect_init(&pm_server); 471 if(kIOReturnSuccess != err) { 472 return_code = kIOReturnInternalError; 473 goto exit; 474 } 475 476 kern_result = io_pm_assertion_retain_release( pm_server, 477 (int)AssertionID, 478 kIOPMAssertionMIGDoRelease, 479 &disableAppSleep, 480 &enableAppSleep, 481 &return_code); 482 483 if(KERN_SUCCESS != kern_result) { 484 return_code = kIOReturnInternalError; 485 } 486#if !TARGET_OS_IPHONE 487 else if (enableAppSleep) { 488 CFStringRef appSleepString = NULL; 489 490 appSleepString = CFStringCreateWithFormat(NULL, NULL, CFSTR("App released its last power assertion %u"), 491 AssertionID); 492 __CFRunLoopSetOptionsReason(__CFRunLoopOptionsDropAssertion, appSleepString); 493 494 CFRelease(appSleepString); 495 } 496#endif 497 498 pm_connect_close(pm_server); 499exit: 500 return return_code; 501} 502 503 504/****************************************************************************** 505 * IOPMAssertionSetProperty 506 * 507 ******************************************************************************/ 508IOReturn IOPMAssertionSetProperty(IOPMAssertionID theAssertion, CFStringRef theProperty, CFTypeRef theValue) 509{ 510 IOReturn return_code = kIOReturnError; 511 kern_return_t kern_result = KERN_SUCCESS; 512 mach_port_t pm_server = MACH_PORT_NULL; 513 CFDataRef sendData = NULL; 514 CFDictionaryRef sendDict = NULL; 515 int disableAppSleep = 0; 516 int enableAppSleep = 0; 517 518 if (!theAssertion) { 519 return_code = kIOReturnBadArgument; 520 goto exit; 521 } 522 523 return_code = pm_connect_init(&pm_server); 524 525 if(kIOReturnSuccess != return_code) { 526 goto exit; 527 } 528 529 sendDict = CFDictionaryCreate(0, (const void **)&theProperty, (const void **)&theValue, 1, 530 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 531 532 if (sendDict) { 533 sendData = CFPropertyListCreateData(0, sendDict, kCFPropertyListBinaryFormat_v1_0, 0, NULL /* error */); 534 CFRelease(sendDict); 535 } 536 537 538 kern_result = io_pm_assertion_set_properties(pm_server, 539 (int)theAssertion, 540 (vm_offset_t)CFDataGetBytePtr(sendData), 541 CFDataGetLength(sendData), 542 &disableAppSleep, 543 &enableAppSleep, 544 (int *)&return_code); 545 546 if(KERN_SUCCESS != kern_result) { 547 return_code = kIOReturnInternalError; 548 goto exit; 549 } 550#if !TARGET_OS_IPHONE 551 else if (disableAppSleep) { 552 CFStringRef appSleepString = NULL; 553 554 appSleepString = CFStringCreateWithFormat(NULL, NULL, CFSTR("App is holding power assertion %u"), 555 theAssertion); 556 __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion, appSleepString); 557 558 CFRelease(appSleepString); 559 } 560 else if (enableAppSleep) { 561 CFStringRef appSleepString = NULL; 562 563 appSleepString = CFStringCreateWithFormat(NULL, NULL, CFSTR("App released its last power assertion %u"), 564 theAssertion); 565 __CFRunLoopSetOptionsReason(__CFRunLoopOptionsDropAssertion, appSleepString); 566 567 CFRelease(appSleepString); 568 } 569#endif 570 571 572exit: 573 if (sendData) 574 CFRelease(sendData); 575 576 if (MACH_PORT_NULL != pm_server) { 577 pm_connect_close(pm_server); 578 } 579 return return_code; 580} 581 582/****************************************************************************** 583 * IOPMAssertionSetTimeout 584 * 585 ******************************************************************************/ 586IOReturn IOPMAssertionSetTimeout(IOPMAssertionID whichAssertion, 587 CFTimeInterval timeoutInterval) 588{ 589 IOReturn return_code = kIOReturnError; 590 CFNumberRef intervalNum = NULL; 591 int timeoutSecs = (int)timeoutInterval; 592 593 intervalNum = CFNumberCreate(0, kCFNumberIntType, &timeoutSecs); 594 595 if (intervalNum) 596 { 597 return_code = IOPMAssertionSetProperty(whichAssertion, kIOPMAssertionTimeoutKey, intervalNum); 598 599 CFRelease(intervalNum); 600 } 601 602 return return_code; 603} 604 605/****************************************************************************** 606 * IOPMAssertionDeclareNotificationEvent 607 * 608 ******************************************************************************/ 609 IOReturn IOPMAssertionDeclareNotificationEvent( 610 CFStringRef notificationName, 611 CFTimeInterval secondsToDisplay, 612 IOPMAssertionID *AssertionID) 613{ 614#define TCPKEEPALIVE 1 615#if TCPKEEPALIVE 616 IOPMAssertionID id = kIOPMNullAssertionID; 617 IOReturn ret = kIOReturnSuccess; 618 io_registry_entry_t rootdomain = getPMRootDomainRef(); 619 CFBooleanRef lidIsClosed = NULL; 620 CFBooleanRef desktopMode = NULL; 621 622 if (rootdomain == MACH_PORT_NULL) 623 return kIOReturnInternalError; 624 625 desktopMode = IORegistryEntryCreateCFProperty(rootdomain, 626 CFSTR("DesktopMode"), kCFAllocatorDefault, 0); 627 lidIsClosed = IORegistryEntryCreateCFProperty(rootdomain, 628 CFSTR(kAppleClamshellStateKey), kCFAllocatorDefault, 0); 629 630 if ((kCFBooleanTrue == lidIsClosed) && (kCFBooleanFalse == desktopMode)) { 631 ret = kIOReturnNotReady; 632 goto exit; 633 } 634 635 ret = IOPMAssertionCreateWithDescription( 636 kIOPMAssertDisplayWake, 637 notificationName, NULL, NULL, NULL, 638 secondsToDisplay, kIOPMAssertionTimeoutActionRelease, 639 &id); 640 if (AssertionID) 641 *AssertionID = id; 642 643exit: 644 if (lidIsClosed) CFRelease(lidIsClosed); 645 if (desktopMode) CFRelease(desktopMode); 646 647 return ret; 648#else 649 if (AssertionID) { 650 *AssertionID = kIOPMNullAssertionID; 651 } 652 return kIOReturnUnsupported; 653#endif 654} 655 656/****************************************************************************** 657 * IOPMAssertionDeclareSystemActivity 658 * 659 ******************************************************************************/ 660IOReturn IOPMAssertionDeclareSystemActivity( 661 CFStringRef AssertionName, 662 IOPMAssertionID *AssertionID, 663 IOPMSystemState *SystemState) 664{ 665 IOReturn err; 666 IOReturn return_code = kIOReturnError; 667 mach_port_t pm_server = MACH_PORT_NULL; 668 kern_return_t kern_result = KERN_SUCCESS; 669 670 CFMutableDictionaryRef properties = NULL; 671 CFDataRef flattenedProps = NULL; 672 673 if (!AssertionName || !AssertionID || !SystemState) { 674 return_code = kIOReturnBadArgument; 675 goto exit; 676 } 677 678 err = pm_connect_init(&pm_server); 679 if(kIOReturnSuccess != err) { 680 return_code = kIOReturnInternalError; 681 goto exit; 682 } 683 684 properties = CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks, 685 &kCFTypeDictionaryValueCallBacks); 686 CFDictionarySetValue(properties, kIOPMAssertionNameKey, AssertionName); 687 688 689 if (collectBackTrace) { 690 saveBackTrace(properties); 691 } 692 693 flattenedProps = CFPropertyListCreateData(0, properties, 694 kCFPropertyListBinaryFormat_v1_0, 0, NULL /* error */); 695 if (!flattenedProps) { 696 return_code = kIOReturnBadArgument; 697 goto exit; 698 } 699 700 kern_result = io_pm_declare_system_active( 701 pm_server, 702 (int *)SystemState, 703 (vm_offset_t)CFDataGetBytePtr(flattenedProps), 704 CFDataGetLength(flattenedProps), 705 (int *)AssertionID, 706 &return_code); 707 708 if(KERN_SUCCESS != kern_result) { 709 return_code = kIOReturnInternalError; 710 goto exit; 711 } 712exit: 713 if (flattenedProps) 714 CFRelease(flattenedProps); 715 716 if (properties) 717 CFRelease(properties); 718 719 if (MACH_PORT_NULL != pm_server) { 720 pm_connect_close(pm_server); 721 } 722 723 return return_code; 724 725} 726/****************************************************************************** 727 * IOPMAssertionDeclareUserActivity 728 * 729 ******************************************************************************/ 730IOReturn IOPMAssertionDeclareUserActivity( 731 CFStringRef AssertionName, 732 IOPMUserActiveType userType, 733 IOPMAssertionID *AssertionID) 734{ 735 736 IOReturn return_code = kIOReturnError; 737 mach_port_t pm_server = MACH_PORT_NULL; 738 kern_return_t kern_result = KERN_SUCCESS; 739 IOReturn err; 740 static struct timeval prev_ts = {0,0}; 741 struct timeval ts; 742 int disableAppSleep = 0; 743 744 745 CFMutableDictionaryRef properties = NULL; 746 CFDataRef flattenedProps = NULL; 747 748 if (!AssertionName || !AssertionID) { 749 return_code = kIOReturnBadArgument; 750 goto exit; 751 } 752 753 gettimeofday(&ts, NULL); 754 if (ts.tv_sec - prev_ts.tv_sec <= 5) { 755 if ( *AssertionID == kIOPMNullAssertionID ) 756 *AssertionID = 0xabcd; /* Give a dummy id */ 757 return_code = kIOReturnSuccess; 758 goto exit; 759 } 760 prev_ts = ts; 761 762 err = pm_connect_init(&pm_server); 763 if(kIOReturnSuccess != err) { 764 return_code = kIOReturnInternalError; 765 goto exit; 766 } 767 768 properties = CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks, 769 &kCFTypeDictionaryValueCallBacks); 770 CFDictionarySetValue(properties, kIOPMAssertionNameKey, AssertionName); 771 772 if (collectBackTrace) { 773 saveBackTrace(properties); 774 } 775 776 flattenedProps = CFPropertyListCreateData(0, properties, 777 kCFPropertyListBinaryFormat_v1_0, 0, NULL /* error */); 778 if (!flattenedProps) { 779 return_code = kIOReturnBadArgument; 780 goto exit; 781 } 782 783 kern_result = io_pm_declare_user_active( 784 pm_server, 785 userType, 786 (vm_offset_t)CFDataGetBytePtr(flattenedProps), 787 CFDataGetLength(flattenedProps), 788 (int *)AssertionID, 789 &disableAppSleep, 790 &return_code); 791 792 793 if(KERN_SUCCESS != kern_result) { 794 return_code = kIOReturnInternalError; 795 goto exit; 796 } 797#if !TARGET_OS_IPHONE 798 else if (disableAppSleep) { 799 __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion, 800 CFSTR("App is holding 'DeclareUserActivity' power assertion")); 801 } 802#endif 803 804 805exit: 806 if (flattenedProps) 807 CFRelease(flattenedProps); 808 809 if (properties) 810 CFRelease(properties); 811 812 if (MACH_PORT_NULL != pm_server) { 813 pm_connect_close(pm_server); 814 } 815 816 return return_code; 817} 818 819 820/****************************************************************************** 821 * IOPMDeclareNetworkClientActivity 822 * 823 ******************************************************************************/ 824IOReturn IOPMDeclareNetworkClientActivity( 825 CFStringRef AssertionName, 826 IOPMAssertionID *AssertionID) 827{ 828 829 IOReturn return_code = kIOReturnError; 830 mach_port_t pm_server = MACH_PORT_NULL; 831 kern_return_t kern_result = KERN_SUCCESS; 832 IOReturn err; 833 int disableAppSleep = 0; 834 835 836 CFMutableDictionaryRef properties = NULL; 837 CFDataRef flattenedProps = NULL; 838 839 if (!AssertionName || !AssertionID) { 840 return_code = kIOReturnBadArgument; 841 goto exit; 842 } 843 844 err = pm_connect_init(&pm_server); 845 if(kIOReturnSuccess != err) { 846 return_code = kIOReturnInternalError; 847 goto exit; 848 } 849 850 properties = CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks, 851 &kCFTypeDictionaryValueCallBacks); 852 CFDictionarySetValue(properties, kIOPMAssertionNameKey, AssertionName); 853 854 if (collectBackTrace) { 855 saveBackTrace(properties); 856 } 857 858 flattenedProps = CFPropertyListCreateData(0, properties, 859 kCFPropertyListBinaryFormat_v1_0, 0, NULL /* error */); 860 if (!flattenedProps) { 861 return_code = kIOReturnBadArgument; 862 goto exit; 863 } 864 865 kern_result = io_pm_declare_network_client_active( 866 pm_server, 867 (vm_offset_t)CFDataGetBytePtr(flattenedProps), 868 CFDataGetLength(flattenedProps), 869 (int *)AssertionID, 870 &disableAppSleep, 871 &return_code); 872 873 874 if(KERN_SUCCESS != kern_result) { 875 return_code = kIOReturnInternalError; 876 goto exit; 877 } 878#if !TARGET_OS_IPHONE 879 else if (disableAppSleep) { 880 __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion, 881 CFSTR("App is holding 'DeclareNetworkClientActivity' power assertion")); 882 } 883#endif 884 885 886exit: 887 if (flattenedProps) 888 CFRelease(flattenedProps); 889 890 if (properties) 891 CFRelease(properties); 892 893 if (MACH_PORT_NULL != pm_server) { 894 pm_connect_close(pm_server); 895 } 896 897 return return_code; 898} 899 900/*****************************************************************************/ 901IOReturn IOPMSetReservePowerMode(bool enable) 902{ 903 904 mach_port_t pm_server = MACH_PORT_NULL; 905 kern_return_t kern_result = KERN_SUCCESS; 906 IOReturn return_code; 907 int rc = kIOReturnSuccess; 908 909 return_code = _pm_connect(&pm_server); 910 911 if(pm_server == MACH_PORT_NULL) 912 return kIOReturnNotReady; 913 914 915 kern_result = io_pm_set_value_int( pm_server, kIOPMSetReservePowerMode, enable ? 1 : 0, &rc); 916 _pm_disconnect(pm_server); 917 918 if (rc != kIOReturnSuccess) 919 return rc; 920 921 return kern_result; 922} 923 924 925/****************************************************************************** 926 * IOPMCopyAssertionsByProcess 927 * 928 ******************************************************************************/ 929IOReturn IOPMCopyAssertionsByProcess(CFDictionaryRef *AssertionsByPid) 930{ 931 IOReturn return_code = kIOReturnError; 932 CFArrayRef flattenedDictionary = NULL; 933 int flattenedArrayCount = 0; 934 CFNumberRef *newDictKeys = NULL; 935 CFArrayRef *newDictValues = NULL; 936 937 if (!AssertionsByPid) 938 return kIOReturnBadArgument; 939 940 return_code = _copyPMServerObject(kIOPMAssertionMIGCopyAll, 0, (CFTypeRef *)&flattenedDictionary); 941 942 if (kIOReturnSuccess != return_code) 943 goto exit; 944 945 /* 946 * This API returns a dictionary whose keys are process ID's. 947 * This is perfectly acceptable in CoreFoundation, EXCEPT that you cannot 948 * serialize a dictionary with CFNumbers for keys using CF or IOKit 949 * serialization. 950 * 951 * To serialize this dictionary and pass it from configd to the caller's process, 952 * we re-formatted it as a "flattened" array of dictionaries in configd, 953 * and we will re-constitute with pid's for keys here. 954 * 955 * Next time around, I will simply not use CFNumberRefs for keys in API. 956 */ 957 958 959 if (flattenedDictionary) { 960 flattenedArrayCount = CFArrayGetCount(flattenedDictionary); 961 } 962 963 if (0 == flattenedArrayCount) { 964 goto exit; 965 } 966 967 newDictKeys = (CFNumberRef *)malloc(sizeof(CFTypeRef) * flattenedArrayCount); 968 newDictValues = (CFArrayRef *)malloc(sizeof(CFTypeRef) * flattenedArrayCount); 969 970 if (!newDictKeys || !newDictValues) 971 goto exit; 972 973 for (int i=0; i < flattenedArrayCount; i++) 974 { 975 CFDictionaryRef dictionaryAtIndex = NULL; 976 977 if ((dictionaryAtIndex = CFArrayGetValueAtIndex(flattenedDictionary, i))) 978 { 979 980 newDictKeys[i] = CFDictionaryGetValue(dictionaryAtIndex, kIOPMAssertionPIDKey); 981 newDictValues[i] = CFDictionaryGetValue(dictionaryAtIndex, CFSTR("PerTaskAssertions")); 982 } 983 } 984 985 *AssertionsByPid = CFDictionaryCreate(kCFAllocatorDefault, 986 (const void **)newDictKeys, (const void **)newDictValues, flattenedArrayCount, 987 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 988 989 return_code = kIOReturnSuccess; 990 991exit: 992 if (newDictKeys) 993 free(newDictKeys); 994 if (newDictValues) 995 free(newDictValues); 996 if (flattenedDictionary) 997 CFRelease(flattenedDictionary); 998 return return_code; 999} 1000 1001/****************************************************************************** 1002 * IOPMAssertionCopyProperties 1003 * 1004 ******************************************************************************/ 1005CFDictionaryRef IOPMAssertionCopyProperties(IOPMAssertionID theAssertion) 1006{ 1007 CFDictionaryRef theResult = NULL; 1008 1009 _copyPMServerObject(kIOPMAssertionMIGCopyOneAssertionProperties, theAssertion, (CFTypeRef *)&theResult); 1010 1011 return theResult; 1012} 1013 1014/****************************************************************************** 1015 * IOPMCopyAssertionsStatus 1016 * 1017 ******************************************************************************/ 1018IOReturn IOPMCopyAssertionsStatus(CFDictionaryRef *AssertionsStatus) 1019{ 1020 if (!AssertionsStatus) 1021 return kIOReturnBadArgument; 1022 1023 return _copyPMServerObject(kIOPMAssertionMIGCopyStatus, 0, (CFTypeRef *)AssertionsStatus); 1024} 1025 1026/****************************************************************************** 1027 * _copyPMServerObject 1028 * 1029 ******************************************************************************/ 1030__private_extern__ IOReturn _copyPMServerObject(int selector, int assertionID, CFTypeRef *objectOut) 1031{ 1032 IOReturn return_code = kIOReturnError; 1033 kern_return_t kern_result = KERN_SUCCESS; 1034 mach_port_t pm_server = MACH_PORT_NULL; 1035 vm_offset_t theResultsPtr = 0; 1036 mach_msg_type_number_t theResultsCnt = 0; 1037 CFDataRef theResultData = NULL; 1038 1039 *objectOut = NULL; 1040 1041 if(kIOReturnSuccess != (return_code = pm_connect_init(&pm_server))) { 1042 return kIOReturnNotFound; 1043 } 1044 1045 kern_result = io_pm_assertion_copy_details(pm_server, assertionID, selector, 1046 &theResultsPtr, &theResultsCnt, &return_code); 1047 1048 if(KERN_SUCCESS != kern_result) { 1049 return kIOReturnInternalError; 1050 } 1051 1052 if (return_code != kIOReturnSuccess) 1053 return return_code; 1054 1055 if ((theResultData = CFDataCreate(0, (const UInt8 *)theResultsPtr, (CFIndex)theResultsCnt))) 1056 { 1057 *objectOut = CFPropertyListCreateWithData(0, theResultData, kCFPropertyListImmutable, NULL, NULL); 1058 CFRelease(theResultData); 1059 } 1060 1061 if (theResultsPtr && 0 != theResultsCnt) { 1062 vm_deallocate(mach_task_self(), theResultsPtr, theResultsCnt); 1063 } 1064 1065 if (MACH_PORT_NULL != pm_server) { 1066 pm_connect_close(pm_server); 1067 } 1068 1069 return kIOReturnSuccess; 1070} 1071 1072 1073/****************************************************************************** 1074 * IOPMCopyAssertionActivityLog 1075 * 1076 ******************************************************************************/ 1077IOReturn IOPMCopyAssertionActivityLog(CFArrayRef *activityLog, bool *overflow) 1078{ 1079 static uint32_t refCnt = UINT_MAX; 1080 1081 return IOPMCopyAssertionActivityUpdate(activityLog, overflow, &refCnt); 1082 1083} 1084 1085IOReturn IOPMCopyAssertionActivityUpdate(CFArrayRef *logUpdates, bool *overflow, uint32_t *refCnt) 1086{ 1087 1088 uint32_t of; 1089 IOReturn rc = kIOReturnInternalError; 1090 CFDataRef unfolder = NULL; 1091 vm_offset_t logPtr = NULL; 1092 mach_port_t pm_server = MACH_PORT_NULL; 1093 kern_return_t kern_result; 1094 mach_msg_type_number_t logSize = 0; 1095 1096 *logUpdates = NULL; 1097 _pm_connect(&pm_server); 1098 1099 if(pm_server == MACH_PORT_NULL) 1100 return NULL; 1101 1102 kern_result = io_pm_assertion_activity_log(pm_server, 1103 &logPtr, &logSize, 1104 refCnt, &of, &rc); 1105 1106 if ((KERN_SUCCESS != kern_result) || (rc != kIOReturnSuccess)) { 1107 goto exit; 1108 } 1109 1110 if (logSize == 0) { 1111 goto exit; 1112 } 1113 1114 unfolder = CFDataCreateWithBytesNoCopy(0, (const UInt8 *)logPtr, (CFIndex)logSize, kCFAllocatorNull); 1115 if (unfolder) 1116 { 1117 *logUpdates = CFPropertyListCreateWithData(0, unfolder, 1118 kCFPropertyListMutableContainers, 1119 NULL, NULL); 1120 CFRelease(unfolder); 1121 } 1122 1123 if (overflow) { 1124 *overflow = of ? true : false; 1125 } 1126 1127exit: 1128 1129 if (logPtr && logSize) { 1130 vm_deallocate(mach_task_self(), logPtr, logSize); 1131 } 1132 1133 if (MACH_PORT_NULL != pm_server) 1134 pm_connect_close(pm_server); 1135 1136 return rc; 1137 1138} 1139 1140/*****************************************************************************/ 1141IOReturn IOPMSetAssertionActivityLog(bool enable) 1142{ 1143 1144 mach_port_t pm_server = MACH_PORT_NULL; 1145 kern_return_t kern_result = KERN_SUCCESS; 1146 IOReturn return_code; 1147 int rc = kIOReturnSuccess; 1148 1149 return_code = _pm_connect(&pm_server); 1150 1151 if(pm_server == MACH_PORT_NULL) 1152 return kIOReturnNotReady; 1153 1154 1155 kern_result = io_pm_set_value_int( pm_server, kIOPMSetAssertionActivityLog, enable ? 1 : 0, &rc); 1156 _pm_disconnect(pm_server); 1157 1158 return kern_result; 1159} 1160/*****************************************************************************/ 1161IOReturn IOPMSetAssertionActivityAggregate(bool enable) 1162{ 1163 1164 mach_port_t pm_server = MACH_PORT_NULL; 1165 kern_return_t kern_result = KERN_SUCCESS; 1166 IOReturn return_code; 1167 int rc = kIOReturnSuccess; 1168 1169 return_code = _pm_connect(&pm_server); 1170 1171 if(pm_server == MACH_PORT_NULL) 1172 return kIOReturnNotReady; 1173 1174 1175 kern_result = io_pm_set_value_int( pm_server, kIOPMSetAssertionActivityAggregate, enable ? 1 : 0, &rc); 1176 _pm_disconnect(pm_server); 1177 1178 return kern_result; 1179} 1180 1181 1182/*****************************************************************************/ 1183CFDictionaryRef IOPMCopyAssertionActivityAggregate( ) 1184{ 1185 IOReturn rc = kIOReturnInternalError; 1186 CFDataRef unfolder = NULL; 1187 mach_port_t pm_server = MACH_PORT_NULL; 1188 kern_return_t kern_result; 1189 vm_offset_t addr = NULL; 1190 mach_msg_type_number_t size = 0; 1191 CFDictionaryRef statsData = NULL; 1192 1193 1194 _pm_connect(&pm_server); 1195 1196 if(pm_server == MACH_PORT_NULL) 1197 return NULL; 1198 1199 kern_result = io_pm_assertion_activity_aggregate(pm_server, 1200 &addr, &size, 1201 &rc); 1202 1203 if ((KERN_SUCCESS != kern_result) || (rc != kIOReturnSuccess)) { 1204 goto exit; 1205 } 1206 1207 unfolder = CFDataCreateWithBytesNoCopy(0, (const UInt8 *)addr, (CFIndex)size, kCFAllocatorNull); 1208 if (unfolder) 1209 { 1210 statsData = CFPropertyListCreateWithData(0, unfolder, 1211 kCFPropertyListMutableContainers, NULL, NULL); 1212 CFRelease(unfolder); 1213 } 1214 1215exit: 1216 1217 if (addr && size) 1218 vm_deallocate(mach_task_self(), addr, size); 1219 1220 1221 if (MACH_PORT_NULL != pm_server) 1222 pm_connect_close(pm_server); 1223 1224 return statsData; 1225} 1226/*****************************************************************************/ 1227void IOPMAssertionSetBTCollection(bool enable) 1228{ 1229 int collectBackTraceToken = 0; 1230 1231 notify_register_check(kIOPMAssertionsCollectBTString, &collectBackTraceToken); 1232 notify_set_state(collectBackTraceToken, enable ? 1 : 0); 1233 notify_post(kIOPMAssertionsCollectBTString); 1234 notify_cancel(collectBackTraceToken); 1235} 1236