1/* 2 * Copyright (c) 2005-2013 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#include <IOKit/pwr_mgt/IOPMLibPrivate.h> 24 25#include <unistd.h> 26#include <stdlib.h> 27#include <notify.h> 28#include <asl.h> 29#include <mach/mach.h> 30#include <mach/mach_host.h> 31#include <mach/mach_error.h> 32#include <servers/bootstrap.h> 33#include <dispatch/dispatch.h> 34#include <bsm/libbsm.h> 35#include <libproc.h> 36 37 38 39#include "PMConnection.h" 40#include "PrivateLib.h" 41#include "PMSettings.h" 42#include "PMAssertions.h" 43#include "BatteryTimeRemaining.h" 44#include "PMStore.h" 45#include "powermanagementServer.h" 46#include "SystemLoad.h" 47#include "Platform.h" 48 49//#include <IOKit/IOReportMacros.h> 50 51#define kIOPMAppName "Power Management configd plugin" 52#define kIOPMPrefsPath "com.apple.PowerManagement.xml" 53#define FMMD_WIPE_BOOT_ARG "fmm-wipe-system-status" 54 55 56#define kMaxAssertions 10240 57 58// CAST_PID_TO_KEY casts a mach_port_t into a void * for CF containers 59#define CAST_PID_TO_KEY(x) ((void *)(uintptr_t)(x)) 60 61#define LEVEL_FOR_BIT(idx) (getAssertionLevel(idx)) 62 63 64 65// Selectors for AppleSmartBatteryManagerUserClient 66enum { 67 kSBUCInflowDisable = 0, 68 kSBUCChargeInhibit = 1 69}; 70 71typedef enum { 72 kTimerTypeTimedOut = 0, 73 kTimerTypeReleased = 1 74} TimerType; 75 76enum { 77 kIOPMSystemActivityAssertionDisabled = 0, 78 kIOPMSystemActivityAssertionEnabled = 1 79}; 80 81 82/* 83 * Maximum delay allowed(in Mins) for turning off the display after the 84 * PreventDisplayIdleSleep assertion is released 85 */ 86#define kPMMaxDisplayTurnOffDelay (5) 87 88 89// Globals 90 91uint32_t gSAAssertionBehaviorFlags = kIOPMSystemActivityAssertionEnabled; 92 93CFArrayRef copyScheduledPowerEvents(void); 94CFDictionaryRef copyRepeatPowerEvents(void); 95 96// forward 97 98static void sendSmartBatteryCommand(uint32_t which, uint32_t level); 99static void sendUserAssertionsToKernel(uint32_t user_assertions); 100static void evaluateAssertions(void); 101static void HandleProcessExit(pid_t deadPID); 102 103static bool callerIsEntitledToAssertion(audit_token_t token, 104 CFDictionaryRef newAssertionProperties); 105#if !TARGET_OS_EMBEDDED 106__private_extern__ void logASLAssertionsAggregate( ); 107 108#else 109#define logASLAssertionsAggregate() 110#endif 111 112static bool propertiesDictRequiresRoot(CFDictionaryRef props); 113static IOReturn doRetain(pid_t pid, IOPMAssertionID id); 114static IOReturn doRelease(pid_t pid, IOPMAssertionID id); 115static IOReturn doSetProperties(pid_t pid, 116 IOPMAssertionID id, 117 CFDictionaryRef props); 118 119static CFArrayRef copyPIDAssertionDictionaryFlattened(void); 120static CFDictionaryRef copyAggregateValuesDictionary(void); 121 122static IOReturn doCreate(pid_t pid, CFMutableDictionaryRef newProperties, 123 IOPMAssertionID *assertion_id, ProcessInfo **pinfo); 124static IOReturn copyAssertionForID(pid_t inPID, int inID, 125 CFMutableDictionaryRef *outAssertion); 126 127static ProcessInfo* processInfoCreate(pid_t p); 128static ProcessInfo* processInfoRetain(pid_t p); 129static void processInfoRelease(pid_t p); 130static ProcessInfo* processInfoGet(pid_t p); 131static void sendActivityTickle (); 132static void setClamshellSleepState(int clamshellSleepState); 133static int getAssertionTypeIndex(CFStringRef type); 134 135static void handleAssertionTimeout(assertionType_t *assertType); 136static void resetGlobalTimer(assertionType_t *assertType, uint64_t timer); 137static IOReturn raiseAssertion(assertion_t *assertion); 138static void allocStatsBuf(ProcessInfo *pinfo); 139 140__private_extern__ bool isDisplayAsleep( ); 141__private_extern__ void logASLMessageSleepServiceTerminated(int forcedTimeoutCnt); 142 143// globals 144static uint32_t kerAssertionBits = 0; 145static int aggregate_assertions; 146static CFStringRef assertion_types_arr[kIOPMNumAssertionTypes]; 147 148static CFMutableDictionaryRef gAssertionsArray = NULL; 149static CFMutableDictionaryRef gUserAssertionTypesDict = NULL; 150CFMutableDictionaryRef gProcessDict = NULL; 151assertionType_t gAssertionTypes[kIOPMNumAssertionTypes]; 152assertionEffect_t gAssertionEffects[kMaxAssertionEffects]; 153uint32_t gDisplaySleepTimer = 0; /* Display Sleep timer value in mins */ 154unsigned long gIdleSleepTimer = 0; /* Idle Sleep timer value in mins */ 155 156extern uint32_t gDebugFlags; 157static IOPMAssertionID gDarkWakeNetworkAssertion = kIOPMNullAssertionID; 158 159/* Number of procs interested in kIOPMAssertionsAnyChangedNotifyString notification */ 160static uint32_t gAnyChange = 0; 161/* Number of procs interested in kIOPMAssertionsChangedNotifyString notification */ 162static uint32_t gAggChange = 0; 163/* Number of procs interested in kIOPMAssertionTimedOutNotifyString notification */ 164static uint32_t gTimeoutChange = 0; 165 166uint32_t gActivityAggCnt = 0; // Number of requests received to enable activity aggregation 167 168#pragma mark - 169#pragma mark MIG 170 171/****************************************************************************** 172 ****************************************************************************** 173 ****************************************************************************** 174 * MIG Handlers 175 ****************************************************************************** 176 ****************************************************************************** 177 *****************************************************************************/ 178#if !TARGET_OS_EMBEDDED 179void updateAppSleepStates(ProcessInfo *pinfo, int *disableAppSleep, int *enableAppSleep) 180{ 181 if (!pinfo) return; 182 183 if ((disableAppSleep) && (pinfo->disableAS_pend == true)) { 184 *disableAppSleep = 1; 185 pinfo->disableAS_pend = false; 186 } 187 if ((enableAppSleep) && (pinfo->enableAS_pend == true)) { 188 *enableAppSleep = 1; 189 pinfo->enableAS_pend = false; 190 } 191} 192#endif 193 194kern_return_t _io_pm_assertion_create ( 195 mach_port_t server __unused, 196 audit_token_t token, 197 vm_offset_t props, 198 mach_msg_type_number_t propsCnt, 199 int *assertion_id, 200 int *disableAppSleep, 201 int *return_code) 202{ 203 CFMutableDictionaryRef newAssertionProperties = NULL; 204 CFDataRef unfolder = NULL; 205 pid_t callerPID = -1; 206 uid_t callerUID = -1; 207 gid_t callerGID = -1; 208 ProcessInfo *pinfo = NULL; 209 210 audit_token_to_au32(token, NULL, NULL, NULL, &callerUID, &callerGID, &callerPID, NULL, NULL); 211 212 *disableAppSleep = 0; 213 unfolder = CFDataCreateWithBytesNoCopy(0, (const UInt8 *)props, propsCnt, kCFAllocatorNull); 214 if (unfolder) { 215 newAssertionProperties = (CFMutableDictionaryRef) 216 CFPropertyListCreateWithData( 0, unfolder, 217 kCFPropertyListMutableContainersAndLeaves, 218 NULL, NULL); 219 CFRelease(unfolder); 220 } 221 222 if (!newAssertionProperties) { 223 *return_code = kIOReturnBadArgument; 224 goto exit; 225 } 226 227 228 if (!callerIsEntitledToAssertion(token, newAssertionProperties)) 229 { 230 *return_code = kIOReturnNotPrivileged; 231 goto exit; 232 } 233 234 // Check for privileges if the assertion requires it. 235 if (propertiesDictRequiresRoot(newAssertionProperties) 236 && ( !(callerIsRoot(callerUID) || callerIsAdmin(callerUID, callerGID)))) 237 { 238 *return_code = kIOReturnNotPrivileged; 239 goto exit; 240 } 241 242 *return_code = doCreate(callerPID, newAssertionProperties, (IOPMAssertionID *)assertion_id, &pinfo); 243 244#if !TARGET_OS_EMBEDDED 245 if ((*return_code == kIOReturnSuccess) && (pinfo != NULL) ) { 246 updateAppSleepStates(pinfo, disableAppSleep, NULL); 247 } 248#endif 249 250exit: 251 if (newAssertionProperties) { 252 CFRelease(newAssertionProperties); 253 } 254 255 vm_deallocate(mach_task_self(), props, propsCnt); 256 257 return KERN_SUCCESS; 258} 259 260 261/*****************************************************************************/ 262 263kern_return_t _io_pm_assertion_set_properties ( 264 mach_port_t server __unused, 265 audit_token_t token, 266 int assertion_id, 267 vm_offset_t props, 268 mach_msg_type_number_t propsCnt, 269 int *disableAppSleep, 270 int *enableAppSleep, 271 int *return_code) 272{ 273 CFDictionaryRef setProperties = NULL; 274 CFDataRef unfolder = NULL; 275 pid_t callerPID = -1; 276 277 audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &callerPID, NULL, NULL); 278 279 *disableAppSleep = 0; 280 *enableAppSleep = 0; 281 unfolder = CFDataCreateWithBytesNoCopy(0, (const UInt8 *)props, propsCnt, kCFAllocatorNull); 282 if (unfolder) { 283 setProperties = (CFDictionaryRef)CFPropertyListCreateWithData(0, unfolder, 0, NULL, NULL); 284 CFRelease(unfolder); 285 } 286 287 if (!setProperties) { 288 *return_code = kIOReturnBadArgument; 289 goto exit; 290 } 291 292 *return_code = doSetProperties(callerPID, assertion_id, setProperties); 293#if !TARGET_OS_EMBEDDED 294 if (*return_code == kIOReturnSuccess) { 295 updateAppSleepStates(processInfoGet(callerPID), disableAppSleep, enableAppSleep); 296 } 297#endif 298 299 CFRelease(setProperties); 300 301exit: 302 vm_deallocate(mach_task_self(), props, propsCnt); 303 304 return KERN_SUCCESS; 305 306} 307 308/*****************************************************************************/ 309kern_return_t _io_pm_assertion_retain_release ( 310 mach_port_t server __unused, 311 audit_token_t token, 312 int assertion_id, 313 int action, 314 int *disableAppSleep, 315 int *enableAppSleep, 316 int *return_code) 317{ 318 pid_t callerPID = -1; 319 320 audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &callerPID, NULL, NULL); 321 322 *disableAppSleep = 0; 323 *enableAppSleep = 0; 324 if (kIOPMAssertionMIGDoRetain == action) { 325 *return_code = doRetain(callerPID, assertion_id); 326 } else { 327 *return_code = doRelease(callerPID, assertion_id); 328 } 329#if !TARGET_OS_EMBEDDED 330 if (*return_code == kIOReturnSuccess) { 331 updateAppSleepStates(processInfoGet(callerPID), disableAppSleep, enableAppSleep); 332 } 333#endif 334 return KERN_SUCCESS; 335} 336 337/*****************************************************************************/ 338kern_return_t _io_pm_assertion_copy_details ( 339 mach_port_t server, 340 audit_token_t token, 341 int assertion_id, 342 int whichData, 343 vm_offset_t *assertions, 344 mach_msg_type_number_t *assertionsCnt, 345 int *return_val) 346{ 347 CFTypeRef theCollection = NULL; 348 CFDataRef serializedDetails = NULL; 349 pid_t callerPID = -1; 350 351 352 *return_val = kIOReturnNotFound; 353 354 if (kIOPMAssertionMIGCopyAll == whichData) 355 { 356 theCollection = copyPIDAssertionDictionaryFlattened(); 357 358 } else if (kIOPMAssertionMIGCopyOneAssertionProperties == whichData) 359 { 360 audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &callerPID, NULL, NULL); 361 362 *return_val = copyAssertionForID(callerPID, assertion_id, 363 (CFMutableDictionaryRef *)&theCollection); 364 365 } else if (kIOPMAssertionMIGCopyStatus == whichData) 366 { 367 theCollection = copyAggregateValuesDictionary(); 368 369 } else if (kIOPMPowerEventsMIGCopyScheduledEvents == whichData) 370 { 371 theCollection = copyScheduledPowerEvents(); 372 } 373 else if (kIOPMPowerEventsMIGCopyRepeatEvents == whichData) 374 { 375 theCollection = copyRepeatPowerEvents(); 376 } 377 378 if (!theCollection) { 379 *assertionsCnt = 0; 380 *assertions = 0; 381 *return_val = kIOReturnSuccess; 382 return KERN_SUCCESS; 383 } 384 385 386 serializedDetails = CFPropertyListCreateData(0, theCollection, 387 kCFPropertyListBinaryFormat_v1_0, 0, NULL); 388 389 CFRelease(theCollection); 390 391 if (serializedDetails) 392 { 393 *assertionsCnt = (mach_msg_type_number_t)CFDataGetLength(serializedDetails); 394 395 vm_allocate(mach_task_self(), (vm_address_t *)assertions, *assertionsCnt, TRUE); 396 397 memcpy((void *)*assertions, CFDataGetBytePtr(serializedDetails), *assertionsCnt); 398 399 CFRelease(serializedDetails); 400 401 *return_val = kIOReturnSuccess; 402 } else { 403 *return_val = kIOReturnInternalError; 404 } 405 406 return KERN_SUCCESS; 407} 408 409kern_return_t _io_pm_ctl_assertion_type ( 410 mach_port_t server, 411 audit_token_t token, 412 string_t type, 413 int op, 414 int *return_code) 415{ 416 CFStringRef typeRef = NULL; 417 uid_t callerEUID; 418 int idx; 419 420 *return_code = kIOReturnError; 421 audit_token_to_au32(token, NULL, &callerEUID, NULL, NULL, NULL, NULL, NULL, NULL); 422 if (callerEUID != 0) { 423 *return_code = kIOReturnNotPrivileged; 424 goto exit; 425 } 426 427 if (type && strlen(type)) { 428 typeRef = CFStringCreateWithCString(0, type, kCFStringEncodingUTF8); 429 } 430 if (!isA_CFString(typeRef)) 431 goto exit; 432 433 if ( (idx = getAssertionTypeIndex(typeRef)) < 0 ) { 434 *return_code = kIOReturnBadArgument; 435 goto exit; 436 } 437 438 *return_code = kIOReturnSuccess; 439 if (op == kIOPMDisableAssertionType) { 440 disableAssertionType(idx); 441 } 442 else if (op == kIOPMEnableAssertionType) { 443 enableAssertionType(idx); 444 } 445 else 446 *return_code = kIOReturnBadArgument; 447exit: 448 if (typeRef) CFRelease(typeRef); 449 450 return KERN_SUCCESS; 451 452} 453 454// Changes clamshell sleep state 455// 1 - disabled, 0 - enabled 456static void setClamshellSleepState(int clamshellSleepState) 457{ 458 io_connect_t connect = IO_OBJECT_NULL; 459 const uint64_t in = (uint64_t)clamshellSleepState; 460 static int prevState = -1; 461 462 if ( prevState == clamshellSleepState) return; 463 prevState = clamshellSleepState; 464 465 if ( (connect = getRootDomainConnect()) == IO_OBJECT_NULL) 466 return; 467 468 469 IOConnectCallMethod(connect, kPMSetClamshellSleepState, 470 &in, 1, 471 NULL, 0, NULL, 472 NULL, NULL, NULL); 473 return; 474} 475 476 477static void sendActivityTickle () 478{ 479 io_connect_t connect = IO_OBJECT_NULL; 480 481 SystemLoadUserActiveAssertions(true); 482 if (!isDisplayAsleep( )) 483 return; // Nothing to do when display is on 484 485 if ( (connect = getRootDomainConnect()) == IO_OBJECT_NULL) 486 return; 487 488 IOConnectCallMethod(connect, kPMActivityTickle, 489 NULL, 0, 490 NULL, 0, NULL, 491 NULL, NULL, NULL); 492 493 return; 494 495} 496static void sendUserAssertionsToKernel(uint32_t user_assertions) 497{ 498 io_connect_t connect = IO_OBJECT_NULL; 499 const uint64_t in = (uint64_t)user_assertions; 500 501 if ( (connect = getRootDomainConnect()) == IO_OBJECT_NULL) 502 return; 503 504 IOConnectCallMethod(connect, kPMSetUserAssertionLevels, 505 &in, 1, 506 NULL, 0, NULL, 507 NULL, NULL, NULL); 508 509 return; 510} 511 512#pragma mark - 513#pragma mark Act on assertions 514 515__private_extern__ void PMAssertions_SettingsHaveChanged(void) 516{ 517 static int lastDWBTSetting = -1; 518 int newDWBT = GetPMSettingBool(CFSTR(kIOPMDarkWakeBackgroundTaskKey)); 519 520 if (newDWBT == lastDWBTSetting) { 521 return; 522 } 523 lastDWBTSetting = newDWBT; 524 525 configAssertionType(kBackgroundTaskType, false); 526} 527 528#if HAVE_SMART_BATTERY 529 static void 530sendSmartBatteryCommand(uint32_t which, uint32_t level) 531{ 532 io_service_t sbmanager = MACH_PORT_NULL; 533 io_connect_t sbconnection = MACH_PORT_NULL; 534 kern_return_t kret; 535 uint32_t output_count = 1; 536 uint64_t uc_return = kIOReturnError; 537 uint64_t level_64 = level; 538 539 // Find SmartBattery manager 540 sbmanager = IOServiceGetMatchingService(MACH_PORT_NULL, 541 IOServiceMatching("AppleSmartBatteryManager")); 542 543 if (MACH_PORT_NULL == sbmanager) { 544 goto bail; 545 } 546 547 kret = IOServiceOpen( sbmanager, mach_task_self(), 0, &sbconnection); 548 if (kIOReturnSuccess != kret) { 549 goto bail; 550 } 551 552 IOConnectCallMethod( 553 sbconnection, // connection 554 which, // selector 555 &level_64, // uint64_t *input 556 1, // input Count 557 NULL, // input struct count 558 0, // input struct count 559 &uc_return, // output 560 &output_count, // output count 561 NULL, // output struct 562 0); // output struct count 563 564bail: 565 566 if (MACH_PORT_NULL != sbconnection) { 567 IOServiceClose(sbconnection); 568 } 569 570 if (MACH_PORT_NULL != sbmanager) { 571 IOObjectRelease(sbmanager); 572 } 573 574 return; 575} 576#else /* HAVE_SMART_BATTERY */ 577 578 static void 579sendSmartBatteryCommand(uint32_t which, uint32_t level) 580{ 581 kern_return_t kr; 582 io_iterator_t iter; 583 io_registry_entry_t next; 584 585 do 586 { 587 kr = IOServiceGetMatchingServices(kIOMasterPortDefault, 588 IOServiceMatching("IOPMPowerSource"), &iter); 589 if (kIOReturnSuccess != kr) 590 break; 591 if (MACH_PORT_NULL == iter) 592 break; 593 while ((next = IOIteratorNext(iter))) 594 { 595 kr = IORegistryEntrySetCFProperty(next, 596 (which == kSBUCChargeInhibit) ? 597 CFSTR(kIOPMPSIsChargingKey) : CFSTR(kIOPMPSExternalConnectedKey), 598 level ? kCFBooleanFalse : kCFBooleanTrue); 599 IOObjectRelease(next); 600 } 601 IOObjectRelease(iter); 602 } 603 while (false); 604 return; 605} 606 607#endif /* HAVE_SMART_BATTERY */ 608 609 610__private_extern__ IOReturn _IOPMSetActivePowerProfilesRequiresRoot ( 611 CFDictionaryRef which_profile, 612 int uid, 613 int gid) 614{ 615 IOReturn ret = kIOReturnError; 616 SCPreferencesRef energyPrefs = NULL; 617 618 /* Private call for Power Management use only. 619 PM's configd plugin (our daemon-lite) is the only intended caller 620 of _IOPMSetActivePowerProfilesRequiresRoot. configd will call this 621 only when a running process (like BatteryMonitor) calls 622 IOPMSetActivePowerProfiles() as adimn, root, or console user. 623 configd does the security check there, and then calls _RequiresRoot 624 under configd's own root privileges. Writing out the preferences 625 file using SCPreferences requires root privileges. 626 */ 627 628 if ( (!callerIsRoot(uid) && 629 !callerIsAdmin(uid, gid) && 630 !callerIsConsole(uid, gid)) || 631 ( (-1 == uid) || (-1 == gid) )) 632 { 633 ret = kIOReturnNotPrivileged; 634 goto exit; 635 } 636 637 if (!which_profile) { 638 // We leave most of the input argument vetting for IOPMSetActivePowerProfiles, 639 // which checks the contents of the dictionary. At this point we assume it 640 // is well formed (and that it exists). 641 ret = kIOReturnBadArgument; 642 goto exit; 643 } 644 645 energyPrefs = SCPreferencesCreate( kCFAllocatorDefault, CFSTR(kIOPMAppName), CFSTR(kIOPMPrefsPath) ); 646 if (!energyPrefs) { 647 goto exit; 648 } 649 650 if (!SCPreferencesLock(energyPrefs, true)) 651 { 652 ret = kIOReturnInternalError; 653 goto exit; 654 } 655 656 if (!SCPreferencesSetValue(energyPrefs, CFSTR("ActivePowerProfiles"), which_profile)) { 657 goto exit; 658 } 659 660 if (!SCPreferencesCommitChanges(energyPrefs)) 661 { 662 // handle error 663 if (kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged; 664 else ret = kIOReturnError; 665 goto exit; 666 } 667 668 if (!SCPreferencesApplyChanges(energyPrefs)) 669 { 670 // handle error 671 if (kSCStatusAccessError == SCError()) ret = kIOReturnNotPrivileged; 672 else ret = kIOReturnError; 673 goto exit; 674 } 675 676 ret = kIOReturnSuccess; 677exit: 678 if (energyPrefs) { 679 SCPreferencesUnlock(energyPrefs); 680 CFRelease(energyPrefs); 681 } 682 return ret; 683} 684 685/* 686 * This functions creates assertions required at boot time. 687 */ 688void createOnBootAssertions( ) 689{ 690 CFMutableDictionaryRef assertionDescription = NULL; 691 692 int value; 693 IOReturn ret; 694 /* 695 * For now only 'preventSystemSleep' assertion is created 696 * for FindMyMacd if system is booting in wipe mode. 697 */ 698 ret = getNvramArgInt(FMMD_WIPE_BOOT_ARG, &value); 699 if (ret == kIOReturnSuccess && value > 0) { 700 /* Create 'PreventSystemSleep' assertion */ 701 assertionDescription = _IOPMAssertionDescriptionCreate( 702 kIOPMAssertionTypePreventSystemSleep, 703 CFSTR("com.apple.powermanagement.fmmdwipe"), 704 NULL, CFSTR("Proxy Assertion during FMMD system wipe"), NULL, 705 120, kIOPMAssertionTimeoutActionRelease); 706 707 if (assertionDescription) 708 { 709 /* This assertion should be applied even on battery power */ 710 CFDictionarySetValue(assertionDescription, 711 kIOPMAssertionAppliesToLimitedPowerKey, (CFBooleanRef)kCFBooleanTrue); 712 InternalCreateAssertion(assertionDescription, NULL); 713 714 CFRelease(assertionDescription); 715 } 716 } 717} 718 719/*********************************** 720 * Dynamic Assertions 721 ***********************************/ 722 723 724/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 725 726static CFDictionaryRef copyAggregateValuesDictionary(void) 727{ 728 CFDictionaryRef assertions_info = NULL; 729 CFNumberRef cf_agg_vals[kIOPMNumAssertionTypes]; 730 int i; 731 732 // Massage int values into CFNumbers for CFDictionaryCreate 733 for (i=0; i<kIOPMNumAssertionTypes; i++) 734 { 735 int tmp_bit = getAssertionLevel(i); 736 737 cf_agg_vals[i] = CFNumberCreate(0, kCFNumberIntType, &tmp_bit); 738 } 739 740 // We return the contents of aggregate_assertions packed into a CFDictionary. 741 assertions_info = CFDictionaryCreate( 742 0, 743 (const void **)assertion_types_arr, // type: CFStringRef 744 (const void **)cf_agg_vals, // value: CFNumberRef 745 kIOPMNumAssertionTypes, 746 &kCFTypeDictionaryKeyCallBacks, 747 &kCFTypeDictionaryValueCallBacks); 748 749 // Release CFNumbers 750 for (i=0; i<kIOPMNumAssertionTypes; i++) 751 { 752 CFRelease(cf_agg_vals[i]); 753 } 754 755 // TODO: strip unsupported assertions? 756 757 return assertions_info; 758} 759 760/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 761 762__private_extern__ void _PMAssertionsDriverAssertionsHaveChanged(uint32_t changedDriverAssertions) 763{ 764 if (gAggChange) 765 notify_post( kIOPMAssertionsChangedNotifyString ); 766} 767 768 769#define kDarkWakeNetworkHoldForSeconds 30 770#define kDeviceEnumerationHoldForSeconds (45LL) 771 772#pragma mark - 773#pragma mark powerd-Internal Use Only 774 775 776__private_extern__ CFMutableDictionaryRef _IOPMAssertionDescriptionCreate( 777 CFStringRef AssertionType, 778 CFStringRef Name, 779 CFStringRef Details, 780 CFStringRef HumanReadableReason, 781 CFStringRef LocalizationBundlePath, 782 CFTimeInterval Timeout, 783 CFStringRef TimeoutBehavior) 784{ 785 CFMutableDictionaryRef descriptor = NULL; 786 787 if (!AssertionType || !Name) { 788 return NULL; 789 } 790 791 descriptor = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 792 if (!descriptor) { 793 return NULL; 794 } 795 796 CFDictionarySetValue(descriptor, kIOPMAssertionNameKey, Name); 797 798 int _on = kIOPMAssertionLevelOn; 799 CFNumberRef _on_num = CFNumberCreate(0, kCFNumberIntType, &_on); 800 CFDictionarySetValue(descriptor, kIOPMAssertionLevelKey, _on_num); 801 CFRelease(_on_num); 802 803 CFDictionarySetValue(descriptor, kIOPMAssertionTypeKey, AssertionType); 804 805 if (Details) { 806 CFDictionarySetValue(descriptor, kIOPMAssertionDetailsKey, Details); 807 } 808 if (HumanReadableReason) { 809 CFDictionarySetValue(descriptor, kIOPMAssertionHumanReadableReasonKey, HumanReadableReason); 810 } 811 if (LocalizationBundlePath) { 812 CFDictionarySetValue(descriptor, kIOPMAssertionLocalizationBundlePathKey, LocalizationBundlePath); 813 } 814 if (Timeout) { 815 CFNumberRef Timeout_num = CFNumberCreate(0, kCFNumberDoubleType, &Timeout); 816 CFDictionarySetValue(descriptor, kIOPMAssertionTimeoutKey, Timeout_num); 817 CFRelease(Timeout_num); 818 } 819 if (TimeoutBehavior) 820 { 821 CFDictionarySetValue(descriptor, kIOPMAssertionTimeoutActionKey, TimeoutBehavior); 822 } 823 824 return descriptor; 825} 826 827 828 829__private_extern__ IOReturn InternalCreateAssertion( 830 CFMutableDictionaryRef properties, 831 IOPMAssertionID *outID) 832{ 833 if (!properties) 834 return kIOReturnBadArgument; 835 836 CFRetain(properties); 837 838 CFRunLoopPerformBlock(_getPMRunLoop(), kCFRunLoopDefaultMode, ^{ 839 if (outID == NULL) { 840 /* Some don't care for assertionId */ 841 IOPMAssertionID assertionID = kIOPMNullAssertionID; 842 doCreate(getpid(), properties, &assertionID, NULL); 843 } 844 else if ( *outID == kIOPMNullAssertionID ) 845 doCreate(getpid(), properties, outID, NULL); 846 847 CFRelease(properties); 848 }); 849 CFRunLoopWakeUp(_getPMRunLoop()); 850 851 return kIOReturnSuccess; 852} 853 854__private_extern__ void InternalReleaseAssertion( 855 IOPMAssertionID *outID) 856{ 857 CFRunLoopPerformBlock(_getPMRunLoop(), kCFRunLoopDefaultMode, ^{ 858 if ( *outID != kIOPMNullAssertionID ) { 859 doRelease(getpid(), *outID); 860 } 861 *outID = kIOPMNullAssertionID; 862 }); 863 CFRunLoopWakeUp(_getPMRunLoop()); 864} 865 866__private_extern__ void InternalEvaluateAssertions(void) 867{ 868 CFRunLoopPerformBlock(_getPMRunLoop(), kCFRunLoopDefaultMode, ^{ 869 evaluateAssertions(); 870 }); 871 CFRunLoopWakeUp(_getPMRunLoop()); 872 873} 874 875static IOReturn _localCreateAssertionWithTimer( 876 CFStringRef type, CFStringRef name, int timerSecs, IOPMAssertionID *outID) 877{ 878 CFMutableDictionaryRef dict = NULL; 879 880 if (!type || !name || !outID) { 881 return kIOReturnBadArgument; 882 } 883 884 if ( (dict = _IOPMAssertionDescriptionCreate(type, name, NULL, NULL, NULL, 885 (CFTimeInterval)timerSecs, kIOPMAssertionTimeoutActionRelease)) ) 886 { 887 doCreate(getpid(), dict, outID, NULL); 888 CFRelease(dict); 889 } 890 891 return kIOReturnSuccess; 892 893} 894static IOReturn _localCreateAssertion(CFStringRef type, CFStringRef name, IOPMAssertionID *outID) 895{ 896 return _localCreateAssertionWithTimer(type, name, 0, outID); 897} 898 899static IOReturn _enableAssertionForLimitedPower(pid_t pid, IOPMAssertionID id) 900{ 901 CFMutableDictionaryRef dict = NULL; 902 IOReturn rc = kIOReturnError; 903 904 if (!id) 905 return kIOReturnBadArgument; 906 907 if ((dict = CFDictionaryCreateMutable(0, 0, 908 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) 909 { 910 CFDictionarySetValue(dict, kIOPMAssertionAppliesToLimitedPowerKey, kCFBooleanTrue); 911 912 rc = doSetProperties(pid, id, dict); 913 914 CFRelease(dict); 915 } 916 917 return rc; 918} 919 920/* _DarkWakeHandleNetworkWake runs when PM enters dark wake via network packet. 921 * It creates a temporary assertion that keeps the system awake hopefully long enough 922 * for a remote client to connect, and for the server to create an assertion 923 * keeping the system awak. 924 */ 925static void _DarkWakeHandleNetworkWake(void) 926{ 927 IOReturn rc; 928 929 rc = _localCreateAssertionWithTimer(kIOPMAssertInternalPreventSleep, 930 CFSTR("Network wake delay proxy assertion"), 931 30, &gDarkWakeNetworkAssertion); 932 933 if (rc != kIOReturnSuccess) 934 return; 935 936 /* Enable this assertion on battery power also */ 937 _enableAssertionForLimitedPower(getpid(), gDarkWakeNetworkAssertion); 938 939 return ; 940} 941 942 943 944typedef struct notifyRegInfo { 945 IONotificationPortRef port; 946 io_object_t handle; 947} notifyRegInfo_st; 948 949static void _DeregisterForNotification( 950 notifyRegInfo_st *notifyInfo) 951{ 952 if (notifyInfo->handle) 953 IOObjectRelease(notifyInfo->handle); 954 955 if (notifyInfo->port) 956 IONotificationPortDestroy(notifyInfo->port); 957 958 if (notifyInfo) 959 free(notifyInfo); 960} 961 962/* 963 * Register for specific interestType with service at specified 'path' */ 964static notifyRegInfo_st * _RegisterForNotification( 965 const io_string_t path, const io_name_t interestType, 966 IOServiceInterestCallback callback, void *refCon) 967{ 968 969 io_service_t obj = MACH_PORT_NULL; 970 notifyRegInfo_st *notifyInfo = NULL; 971 kern_return_t kr; 972 973 notifyInfo = calloc(sizeof(notifyRegInfo_st), 1); 974 if ( !notifyInfo ) 975 goto exit; 976 977 notifyInfo->port = IONotificationPortCreate( kIOMasterPortDefault ); 978 if ( !notifyInfo->port ) 979 goto exit; 980 981 obj = IORegistryEntryFromPath( kIOMasterPortDefault, path); 982 if ( !obj ) 983 goto exit; 984 985 kr = IOServiceAddInterestNotification( 986 notifyInfo->port, 987 obj, interestType, 988 callback, refCon, 989 ¬ifyInfo->handle ); 990 991 if (kr != KERN_SUCCESS) 992 goto exit; 993 994 995 IOObjectRelease(obj); 996 return notifyInfo; 997 998exit: 999 if (obj) 1000 IOObjectRelease(obj); 1001 1002 if (notifyInfo) 1003 { 1004 if (notifyInfo->handle) 1005 IOObjectRelease(notifyInfo->handle); 1006 if (notifyInfo->port) 1007 IONotificationPortDestroy(notifyInfo->port); 1008 free(notifyInfo); 1009 } 1010 1011 return NULL; 1012} 1013 1014typedef struct devEnumInfo { 1015 dispatch_source_t dispSrc; /* Dispatched 5sec after IOKit is quiet */ 1016 bool suspended; /* true if 'dispSrc' is suspended */ 1017 dispatch_source_t dispSrc2; /* Dispatched 45sec after assertion is created */ 1018 notifyRegInfo_st *notifyInfo; 1019 IOPMAssertionID assertId; 1020}devEnumInfo_st; 1021 1022/* 1023 * Function that releases the assertion and cleans up all dispatch queues */ 1024static void devEnumerationDone( devEnumInfo_st *deInfo ) 1025{ 1026 1027 /* First cancel the dispatch sources */ 1028 if (deInfo->dispSrc && (dispatch_source_testcancel(deInfo->dispSrc) == 0)) { 1029 dispatch_source_cancel(deInfo->dispSrc); 1030 } 1031 1032 if (deInfo->dispSrc2 && (dispatch_source_testcancel(deInfo->dispSrc2) == 0)) { 1033 dispatch_source_cancel(deInfo->dispSrc2); 1034 } 1035 /* De-register from IOkit busy state updates */ 1036 if (deInfo->notifyInfo) { 1037 _DeregisterForNotification(deInfo->notifyInfo); 1038 deInfo->notifyInfo = 0; 1039 } 1040 1041 /* Release the assertion */ 1042 if (deInfo->assertId) { 1043 doRelease(getpid(), deInfo->assertId); 1044 deInfo->assertId = 0; 1045 free(deInfo); 1046 } 1047} 1048 1049void ioKitStateCallback ( 1050 void * refcon, 1051 io_service_t service, 1052 uint32_t messageType, 1053 void * messageArgument ) 1054{ 1055 devEnumInfo_st *deInfo = (devEnumInfo_st *)refcon; 1056 long state = (long)messageArgument; 1057 dispatch_source_t dispSrc; 1058 1059 1060 if (messageType != kIOMessageServiceBusyStateChange) 1061 return; 1062 1063 if (state) { 1064 /* IOKit is busy. Suspend the timer until the Iokit is free */ 1065 if (deInfo->dispSrc && !deInfo->suspended) { 1066 dispatch_suspend(deInfo->dispSrc); 1067 deInfo->suspended = true; 1068 } 1069 } 1070 else { 1071 /* 1072 * IOkit is free. Create/extend a timer to dispatch a function 1073 * that can release the device enumeration assertion. 1074 */ 1075 if (deInfo->dispSrc == 0) { 1076 dispSrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 1077 0, dispatch_get_main_queue()); 1078 1079 dispatch_source_set_event_handler(dispSrc, ^{ 1080 devEnumerationDone(deInfo); 1081 }); 1082 1083 dispatch_source_set_cancel_handler(dispSrc, ^{ 1084 dispatch_release(dispSrc); 1085 }); 1086 1087 deInfo->dispSrc = dispSrc; 1088 deInfo->suspended = true; 1089 } 1090 if (deInfo->suspended) { 1091 dispatch_source_set_timer(deInfo->dispSrc, dispatch_time(DISPATCH_TIME_NOW, 5LL * NSEC_PER_SEC), 1092 DISPATCH_TIME_FOREVER, 0); 1093 dispatch_resume(deInfo->dispSrc); 1094 } 1095 1096 deInfo->suspended = false; 1097 } 1098 1099 1100} 1101 1102 1103static void _AssertForDeviceEnumeration( ) 1104{ 1105 IOPMAssertionID deviceEnumerationAssertion = kIOPMNullAssertionID; 1106 notifyRegInfo_st *notifyInfo = NULL; 1107 devEnumInfo_st *deInfo = NULL; 1108 IOReturn rc; 1109 dispatch_source_t dispSrc; 1110 1111 rc = _localCreateAssertion(kIOPMAssertInternalPreventSleep, 1112 CFSTR("PM configd - Wait for Device enumeration"), 1113 &deviceEnumerationAssertion); 1114 if (rc != kIOReturnSuccess) 1115 return; 1116 1117 /* Enable this assertion on battery power also */ 1118 _enableAssertionForLimitedPower(getpid(), deviceEnumerationAssertion); 1119 1120 deInfo = calloc(sizeof(devEnumInfo_st), 1); 1121 if (!deInfo) { 1122 goto exit; 1123 } 1124 1125 /* Register IOService Busy/free notifications */ 1126 notifyInfo = _RegisterForNotification(kIOServicePlane ":/", 1127 kIOBusyInterest, ioKitStateCallback, (void *)deInfo); 1128 if ( !notifyInfo ) { 1129 /* Failed to register for notification. Remove the assertion immediately */ 1130 goto exit; 1131 } 1132 1133 deInfo->notifyInfo = notifyInfo; 1134 deInfo->assertId = deviceEnumerationAssertion; 1135 1136 /* 1137 * Create a higher level timer dispatch, which guarantees that assertion is 1138 * released irrespective of the IOkit busy/quiet state. 1139 */ 1140 1141 dispSrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 1142 0, dispatch_get_main_queue()); 1143 dispatch_source_set_timer(dispSrc, 1144 dispatch_time(DISPATCH_TIME_NOW, kDeviceEnumerationHoldForSeconds * NSEC_PER_SEC), 1145 DISPATCH_TIME_FOREVER, 0); 1146 1147 dispatch_source_set_event_handler(dispSrc, ^{ 1148 devEnumerationDone(deInfo); 1149 }); 1150 1151 dispatch_source_set_cancel_handler(dispSrc, ^{ 1152 dispatch_release(dispSrc); 1153 }); 1154 1155 deInfo->dispSrc2 = dispSrc; 1156 dispatch_resume(deInfo->dispSrc2); 1157 1158 1159 IONotificationPortSetDispatchQueue(notifyInfo->port, dispatch_get_main_queue()); 1160 1161 return; 1162 1163exit: 1164 if (deInfo) 1165 free(deInfo); 1166 1167 if (notifyInfo) 1168 _DeregisterForNotification(notifyInfo); 1169 1170 doRelease(getpid(), deviceEnumerationAssertion); 1171} 1172 1173/* 1174 * Create assertions for a short period on behalf of other modules/processes. This is to 1175 * give a chance to those modules to create any required assertions on their own. 1176 * Otherwise, system may go back to sleep before those modules got a chance to 1177 * complete their processing. 1178 */ 1179__private_extern__ void _ProxyAssertions(const struct IOPMSystemCapabilityChangeParameters *capArgs) 1180{ 1181 1182 CFStringRef wakeType = NULL; 1183 CFStringRef wakeReason = NULL; 1184 IOPMAssertionID pushSvcAssert = kIOPMNullAssertionID; 1185 1186 if ( !(kIOPMSystemCapabilityDidChange & capArgs->changeFlags) ) 1187 return; 1188 1189 1190 if ( IOPMIsADarkWake(capArgs->toCapabilities) && 1191 IOPMIsASleep(capArgs->fromCapabilities) ) 1192 { 1193 wakeType = _copyRootDomainProperty(CFSTR(kIOPMRootDomainWakeTypeKey)); 1194 wakeReason = _copyRootDomainProperty(CFSTR(kIOPMRootDomainWakeReasonKey)); 1195 1196 if (isA_CFString(wakeReason) && CFEqual(wakeReason, kIORootDomainWakeReasonDarkPME)) 1197 { 1198 if (isA_CFString(wakeType) && CFEqual(wakeType, kIOPMRootDomainWakeTypeNetwork)) 1199 _DarkWakeHandleNetworkWake( ); 1200 else 1201 _AssertForDeviceEnumeration( ); 1202 } 1203 else if (isA_CFString(wakeType)) 1204 { 1205 if (CFEqual(wakeType, kIOPMRootDomainWakeTypeNetwork)) 1206 _DarkWakeHandleNetworkWake( ); 1207 else if (CFEqual(wakeType, kIOPMRootDomainWakeTypeMaintenance) && 1208 CFEqual(wakeReason, kIOPMRootDomainWakeReasonRTC)) 1209 { 1210 _localCreateAssertionWithTimer(kIOPMAssertionTypeBackgroundTask, 1211 CFSTR("Powerd - Wait for client BackgroundTask assertions"), 10, &pushSvcAssert); 1212 } 1213 else if ((CFEqual(wakeType, kIOPMRootDomainWakeTypeAlarm) == false ) && 1214 (CFEqual(wakeType, kIOPMRootDomainWakeTypeMaintenance) == false ) && 1215 (CFEqual(wakeType, kIOPMRootDomainWakeTypeSleepTimer) == false ) && 1216 (CFEqual(wakeType, kIOPMRootDomainWakeTypeSleepService) == false ) && 1217 (CFEqual(wakeType, kIOPMrootDomainWakeTypeLowBattery) == false ) ) 1218 { 1219 /* 1220 * If this is not a Timer based wake, raise assertion and wait for 1221 * devices to enumerate. 1222 */ 1223 _AssertForDeviceEnumeration( ); 1224 } 1225 } 1226 else 1227 { 1228 /* 1229 * Wake type is not set for some cases. Only wake reason is set. 1230 * Plugging a new USB device while sleeping is one such case 1231 */ 1232 _AssertForDeviceEnumeration( ); 1233 } 1234 1235 if (wakeType) { 1236 CFRelease(wakeType); 1237 } 1238 if (wakeReason) 1239 CFRelease(wakeReason); 1240 } 1241 1242} 1243 1244/* 1245 * Takes an assertion to keep display on for up to 1246 * a max of 'kPMMaxDisplayTurnOffDelay' minutes 1247 */ 1248void delayDisplayTurnOff( ) 1249{ 1250 1251 CFNumberRef levelNum = NULL; 1252 CFNumberRef Timeout_num = NULL; 1253 CFTimeInterval delay = 0; 1254 1255 IOPMAssertionLevel level = kIOPMAssertionLevelOn; 1256 static IOPMAssertionID id = kIOPMNullAssertionID; 1257 CFMutableDictionaryRef dict = NULL; 1258 1259 if (gDisplaySleepTimer) 1260 delay = gDisplaySleepTimer > kPMMaxDisplayTurnOffDelay ? 1261 kPMMaxDisplayTurnOffDelay : gDisplaySleepTimer; 1262 else 1263 delay = kPMMaxDisplayTurnOffDelay; 1264 1265 delay *= 60; 1266 1267 if (id == kIOPMNullAssertionID) 1268 { 1269 dict = _IOPMAssertionDescriptionCreate( 1270 kIOPMAssertInternalPreventDisplaySleep, 1271 CFSTR("com.apple.powermanagement.delayDisplayOff"), 1272 NULL, CFSTR("Proxy to delay display off"), NULL, 1273 (CFTimeInterval)delay, kIOPMAssertionTimeoutActionTurnOff); 1274 1275 if (dict) { 1276 doCreate(getpid(), dict, &id, NULL); 1277 CFRelease(dict); 1278 } 1279 } 1280 else 1281 { 1282 dict = CFDictionaryCreateMutable(0, 0, 1283 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1284 levelNum = CFNumberCreate(0, kCFNumberIntType, &level); 1285 Timeout_num = CFNumberCreate(0, kCFNumberDoubleType, &delay); 1286 1287 if (dict && levelNum && Timeout_num) 1288 { 1289 CFDictionarySetValue(dict, kIOPMAssertionLevelKey, levelNum); 1290 CFDictionarySetValue(dict, kIOPMAssertionTimeoutKey, Timeout_num); 1291 doSetProperties(getpid(), id, dict); 1292 } 1293 if (dict) CFRelease(dict); 1294 if (levelNum) CFRelease(levelNum); 1295 if (Timeout_num) CFRelease(Timeout_num); 1296 } 1297 1298 1299} 1300 1301static bool propertiesDictRequiresRoot(CFDictionaryRef props) 1302{ 1303 if ( CFDictionaryGetValue(props, kIOPMInflowDisableAssertion) 1304 || CFDictionaryGetValue(props, kIOPMChargeInhibitAssertion) ) 1305 { 1306 return true; 1307 } else { 1308 return false; 1309 } 1310} 1311 1312 1313 1314static bool callerIsEntitledToAssertion( 1315 audit_token_t token, 1316 CFDictionaryRef newAssertionProperties) 1317{ 1318 CFStringRef assert_type = NULL; 1319 bool caller_is_allowed = true; 1320 int idx = -1; 1321 1322 assert_type = CFDictionaryGetValue(newAssertionProperties, kIOPMAssertionTypeKey); 1323 idx = getAssertionTypeIndex(assert_type); 1324 if ( (idx < 0) || (gAssertionTypes[idx].entitlement == NULL)) 1325 return true; 1326 1327 caller_is_allowed = auditTokenHasEntitlement(token, gAssertionTypes[idx].entitlement); 1328 1329 return caller_is_allowed; 1330} 1331 1332 1333static ProcessInfo* processInfoCreate(pid_t p) 1334{ 1335 ProcessInfo *proc = NULL; 1336 char name[kProcNameBufLen]; 1337 static uint32_t create_seq = 0; 1338 1339 proc = calloc(1, sizeof(ProcessInfo)); 1340 if (!proc) return NULL; 1341 1342 1343 proc->disp_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, p, 1344 DISPATCH_PROC_EXIT, dispatch_get_main_queue()); 1345 if (proc->disp_src == NULL) { 1346 free(proc); 1347 return NULL; 1348 } 1349 1350 dispatch_source_set_event_handler(proc->disp_src, ^{ 1351 HandleProcessExit(p); 1352 }); 1353 1354 dispatch_source_set_cancel_handler(proc->disp_src, ^{ 1355 dispatch_release(proc->disp_src); 1356 }); 1357 1358 dispatch_resume(proc->disp_src); 1359 1360 proc_name(p, name, sizeof(name)); 1361 proc->name = CFStringCreateWithCString(0, name, kCFStringEncodingUTF8); 1362 proc->pid = p; 1363 proc->retain_cnt++; 1364 proc->create_seq = create_seq++; 1365 1366 CFDictionarySetValue(gProcessDict, (uintptr_t)p, (const void *)proc); 1367 1368 return proc; 1369} 1370 1371/* Wrap a pointer to a non-CF object inside a CFData, so that 1372 * we can place it an a CF container. 1373 */ 1374 1375static ProcessInfo* processInfoRetain(pid_t p) 1376{ 1377 ProcessInfo *proc = NULL; 1378 proc = (ProcessInfo *)CFDictionaryGetValue(gProcessDict, (uintptr_t)p); 1379 1380 if (proc) { 1381 if (proc->retain_cnt != UINT_MAX) proc->retain_cnt++; 1382 return proc; 1383 } 1384 1385 return NULL; 1386 1387} 1388static ProcessInfo* processInfoGet(pid_t p) 1389{ 1390 ProcessInfo *proc = NULL; 1391 proc = (ProcessInfo *)CFDictionaryGetValue(gProcessDict, (uintptr_t)p); 1392 1393 if (proc) { 1394 return proc; 1395 } 1396 1397 return NULL; 1398} 1399 1400CFStringRef processInfoGetName(pid_t p) 1401{ 1402 ProcessInfo *proc = NULL; 1403 CFStringRef retString = NULL; 1404 proc = (ProcessInfo *)CFDictionaryGetValue(gProcessDict, (uintptr_t)p); 1405 1406 if (proc) { 1407 retString = proc->name; 1408 } 1409 1410 return retString; 1411} 1412 1413static void processInfoRelease(pid_t p) 1414{ 1415 ProcessInfo *proc = NULL; 1416 1417 proc = (ProcessInfo *)CFDictionaryGetValue(gProcessDict, (uintptr_t)p); 1418 1419 if (!proc) return; 1420 1421 1422 1423 if (proc->retain_cnt == 1) { 1424 1425 dispatch_release(proc->disp_src); 1426 if (proc->name) CFRelease(proc->name); 1427 CFDictionaryRemoveValue(gProcessDict, (uintptr_t)p); 1428 free(proc); 1429 } 1430 else { 1431 proc->retain_cnt--; 1432 } 1433 return ; 1434} 1435 1436#if !TARGET_OS_EMBEDDED 1437static void disableAppSleep(ProcessInfo *pinfo) 1438{ 1439 char notify_str[128]; 1440 1441 if (pinfo->disableAS_pend == false) 1442 return; 1443 1444 pinfo->disableAS_pend = false; 1445 snprintf(notify_str, sizeof(notify_str), "%s.%d", 1446 kIOPMDisableAppSleepPrefix,pinfo->pid); 1447 notify_post(notify_str); 1448 1449} 1450 1451static void enableAppSleep(ProcessInfo *pinfo) 1452{ 1453 char notify_str[128]; 1454 1455 if (pinfo->enableAS_pend == false) 1456 return; 1457 1458 pinfo->enableAS_pend = false; 1459 snprintf(notify_str, sizeof(notify_str), "%s.%d", 1460 kIOPMEnableAppSleepPrefix, pinfo->pid); 1461 notify_post(notify_str); 1462} 1463#endif 1464 1465 1466void schedDisableAppSleep(assertion_t *assertion) 1467{ 1468#if !TARGET_OS_EMBEDDED 1469 assertionType_t *assertType = NULL; 1470 ProcessInfo *pinfo = NULL; 1471 uint32_t agg; 1472 1473 assertType = &gAssertionTypes[assertion->kassert]; 1474 1475 if ( !(assertType->flags & kAssertionTypePreventAppSleep)) return; 1476 1477 pinfo = assertion->pinfo; 1478 if (pinfo->pid == getpid()) return; 1479 1480 1481 if (pinfo->assert_cnt[assertion->kassert] == UCHAR_MAX) return; 1482 pinfo->assert_cnt[assertion->kassert]++; 1483 1484 agg = pinfo->aggTypes; 1485 pinfo->aggTypes |= ( 1 << assertion->kassert ); 1486 if (agg == 0) { 1487 processInfoRetain(pinfo->pid); 1488 pinfo->disableAS_pend = true; 1489 CFRunLoopPerformBlock(_getPMRunLoop(), kCFRunLoopDefaultMode, 1490 ^{ 1491 disableAppSleep(pinfo); 1492 processInfoRelease(pinfo->pid); 1493 }); 1494 CFRunLoopWakeUp(_getPMRunLoop()); 1495 } 1496#endif 1497} 1498 1499 1500void schedEnableAppSleep(assertion_t *assertion) 1501{ 1502#if !TARGET_OS_EMBEDDED 1503 assertionType_t *assertType = NULL; 1504 ProcessInfo *pinfo = NULL; 1505 1506 assertType = &gAssertionTypes[assertion->kassert]; 1507 if ( !(assertType->flags & kAssertionTypePreventAppSleep)) return; 1508 1509 pinfo = assertion->pinfo; 1510 if (pinfo->pid == getpid()) return; 1511 1512 1513 if (--pinfo->assert_cnt[assertion->kassert] == 0) 1514 { 1515 pinfo->aggTypes &= ~( 1 << assertion->kassert ); 1516 1517 if (pinfo->aggTypes == 0) { 1518 processInfoRetain(pinfo->pid); 1519 pinfo->enableAS_pend = true; 1520 CFRunLoopPerformBlock(_getPMRunLoop(), kCFRunLoopDefaultMode, 1521 ^{ 1522 enableAppSleep(pinfo); 1523 processInfoRelease(pinfo->pid); 1524 }); 1525 CFRunLoopWakeUp(_getPMRunLoop()); 1526 } 1527 } 1528#endif 1529} 1530 1531 1532void updateAppStats(assertion_t *assertion, assertionOps op) 1533{ 1534 assertionType_t *assertType = NULL; 1535 ProcessInfo *pinfo = NULL; 1536 effectStats_t *stats = NULL; 1537 uint64_t duration = 0; 1538 1539 assertType = &gAssertionTypes[assertion->kassert]; 1540 1541 if (gActivityAggCnt && (assertType->effectIdx < kMaxEffectStats)) { 1542 1543 if (assertion->causingPid) { 1544 // If kIOPMAssertionOnBehalfOfPID is set, stats are collected on that process structure 1545 if (assertion->causingPinfo == NULL) { 1546 if (!(assertion->causingPinfo = processInfoRetain(assertion->causingPid))) { 1547 assertion->causingPinfo = processInfoCreate(assertion->causingPid); 1548 1549 // If allocation failed, use the process creating the assertion itself 1550 if (!assertion->causingPinfo) 1551 assertion->causingPinfo = assertion->pinfo; 1552 } 1553 } 1554 1555 pinfo = assertion->causingPinfo; 1556 } 1557 else { 1558 pinfo = assertion->pinfo; 1559 } 1560 1561 if (!pinfo->reportBuf) allocStatsBuf(pinfo); 1562 1563 if (pinfo->reportBuf) 1564 stats = &pinfo->stats[assertType->effectIdx]; 1565 } 1566 1567 switch (op) { 1568 1569 case kAssertionOpRaise: 1570 if ((assertType->flags & kAssertionTypeNotValidOnBatt) && 1571 (!(assertion->state & kAssertionStateValidOnBatt)) && (_getPowerSource() == kBatteryPowered)) { 1572 /* 1573 * If this assertion type is not allowed on battery and this assertion doesn't have override flag, 1574 * then don't let this assertion add to stats 1575 */ 1576 stats = NULL; 1577 } 1578 if (stats && !(assertion->state & kAssertionStateAddsToProcStats)) { 1579 if (stats->cnt++ == 0) { 1580 stats->startTime = getMonotonicTime(); 1581 } 1582 assertion->state |= kAssertionStateAddsToProcStats; 1583 } 1584 break; 1585 1586 case kAssertionOpRelease: 1587 if (stats && (stats->cnt) && (assertion->state & kAssertionStateAddsToProcStats)) { 1588 if (--stats->cnt == 0) { 1589 duration = (getMonotonicTime() - stats->startTime); 1590 SIMPLEARRAY_INCREMENTVALUE(pinfo->reportBuf, assertType->effectIdx, duration); 1591 } 1592 assertion->state &= ~kAssertionStateAddsToProcStats; 1593 } 1594 break; 1595 1596 default: 1597 break; 1598 } 1599 1600} 1601 1602static IOReturn lookupAssertion(pid_t pid, IOPMAssertionID id, assertion_t **assertion) 1603{ 1604 unsigned int idx = INDEX_FROM_ID(id); 1605 assertion_t *tmp_a = NULL; 1606 1607 if (idx >= kMaxAssertions) 1608 return kIOReturnBadArgument; 1609 1610 if( CFDictionaryGetValueIfPresent(gAssertionsArray, 1611 (uintptr_t)idx, (const void **)&tmp_a) == false) 1612 return kIOReturnBadArgument; 1613 1614 if (tmp_a->pinfo->pid != pid) 1615 return kIOReturnNotPermitted; 1616 1617 *assertion = tmp_a; 1618 return kIOReturnSuccess; 1619 1620} 1621 1622kern_return_t _io_pm_change_sa_assertion_behavior ( 1623 mach_port_t server __unused, 1624 audit_token_t token, 1625 uint32_t newFlags, 1626 uint32_t *oldFlags, 1627 int *return_code) 1628{ 1629 pid_t callerPID = -1; 1630 uid_t callerUID = -1; 1631 gid_t callerGID = -1; 1632 1633 audit_token_to_au32(token, NULL, NULL, NULL, &callerUID, &callerGID, &callerPID, NULL, NULL); 1634 if (!callerIsRoot(callerUID)) 1635 { 1636 *return_code = kIOReturnNotPrivileged; 1637 goto exit; 1638 } 1639 1640 if (oldFlags) 1641 *oldFlags = gSAAssertionBehaviorFlags; 1642 gSAAssertionBehaviorFlags = newFlags; 1643 1644 *return_code = kIOReturnSuccess; 1645 1646exit: 1647 return KERN_SUCCESS; 1648} 1649kern_return_t _io_pm_declare_system_active ( 1650 mach_port_t server __unused, 1651 audit_token_t token, 1652 int *system_state, 1653 vm_offset_t props, 1654 mach_msg_type_number_t propsCnt, 1655 int *assertion_id, 1656 int *return_code) 1657{ 1658 pid_t callerPID = -1; 1659 CFDataRef unfolder = NULL; 1660 CFMutableDictionaryRef assertionProperties = NULL; 1661 1662 audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &callerPID, NULL, NULL); 1663 1664 unfolder = CFDataCreateWithBytesNoCopy(0, (const UInt8 *)props, propsCnt, kCFAllocatorNull); 1665 if (unfolder) { 1666 assertionProperties = (CFMutableDictionaryRef)CFPropertyListCreateWithData 1667 (0, unfolder, kCFPropertyListMutableContainersAndLeaves, NULL, NULL); 1668 CFRelease(unfolder); 1669 } 1670 1671 if (!assertionProperties) { 1672 *return_code = kIOReturnBadArgument; 1673 goto exit; 1674 } 1675 *system_state = kIOPMSystemSleepNotReverted; 1676 *return_code = kIOReturnSuccess; 1677 1678 1679 if(_can_revert_sleep()) { 1680 *system_state = kIOPMSystemSleepReverted; 1681 } 1682 else { 1683 CFStringRef sleepReason = _getSleepReason(); 1684 if (CFStringCompare(sleepReason, CFSTR(kIOPMIdleSleepKey), 0) == kCFCompareEqualTo) { 1685 // Schedule an immediate wake if system is going for an idle sleep 1686 int d = 1; 1687 CFNumberRef sleepDuration = CFNumberCreate(kCFAllocatorDefault, 1688 kCFNumberSInt32Type, 1689 &d); 1690 if (sleepDuration) { 1691 _setRootDomainProperty( CFSTR(kIOPMSettingDebugWakeRelativeKey), 1692 sleepDuration); 1693 CFRelease(sleepDuration); 1694 } 1695 } 1696 } 1697 1698 // If set via a backdoor in pmset, this makes 1699 // IOPMAssertionDeclareSystemActivity() behave identically to a 1700 // PreventUserIdleSystemSleep assertion. It negates the side-effect 1701 // behaviors associated with the call 1702 if(gSAAssertionBehaviorFlags != kIOPMSystemActivityAssertionEnabled) 1703 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertionTypePreventUserIdleSystemSleep); 1704 else 1705 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertionTypeSystemIsActive); 1706 1707 if(kIOReturnSuccess != doCreate(callerPID, assertionProperties, (IOPMAssertionID *)assertion_id, NULL)) 1708 *return_code = kIOReturnInternalError; 1709 1710exit: 1711 1712 if (assertionProperties) 1713 CFRelease(assertionProperties); 1714 1715 vm_deallocate(mach_task_self(), props, propsCnt); 1716 1717 return KERN_SUCCESS; 1718} 1719 1720kern_return_t _io_pm_declare_user_active ( 1721 mach_port_t server __unused, 1722 audit_token_t token, 1723 int user_type, 1724 vm_offset_t props, 1725 mach_msg_type_number_t propsCnt, 1726 int *assertion_id, 1727 int *disableAppSleep, 1728 int *return_code) 1729{ 1730 1731 CFMutableDictionaryRef assertionProperties = NULL; 1732 assertion_t *assertion = NULL; 1733 CFDataRef unfolder = NULL; 1734 pid_t callerPID = -1; 1735 IOReturn ret; 1736 bool create_new = true; 1737 CFTimeInterval displaySleepTimerSecs; 1738 CFNumberRef CFdisplaySleepTimer = NULL; 1739 1740 audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &callerPID, NULL, NULL); 1741 1742 *disableAppSleep = 0; 1743 unfolder = CFDataCreateWithBytesNoCopy(0, (const UInt8 *)props, propsCnt, kCFAllocatorNull); 1744 if (unfolder) { 1745 assertionProperties = (CFMutableDictionaryRef) 1746 CFPropertyListCreateWithData(0, unfolder, 1747 kCFPropertyListMutableContainersAndLeaves, 1748 NULL, NULL); 1749 CFRelease(unfolder); 1750 } 1751 1752 if (!assertionProperties) { 1753 *return_code = kIOReturnBadArgument; 1754 goto exit; 1755 } 1756 1757 /* Set the assertion timeout value to display sleep timer value, if it is not 0 */ 1758 1759 displaySleepTimerSecs = gDisplaySleepTimer * 60; /* Convert to secs */ 1760 CFdisplaySleepTimer = CFNumberCreate(0, kCFNumberDoubleType, &displaySleepTimerSecs); 1761 CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutKey, CFdisplaySleepTimer); 1762 CFRelease(CFdisplaySleepTimer); 1763 1764 CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutActionKey, kIOPMAssertionTimeoutActionRelease); 1765 1766 /* Check if this is a repeat call on previously returned assertion id */ 1767 do { 1768 if (assertion_id == NULL || *assertion_id == kIOPMNullAssertionID) 1769 break; 1770 1771 ret = lookupAssertion(callerPID, *assertion_id, &assertion); 1772 if ((kIOReturnSuccess != ret) || !assertion) 1773 break; 1774 1775 if (assertion->kassert != kDeclareUserActivityType) 1776 break; 1777 1778 /* Extend the timeout timer of this assertion by display sleep timer value */ 1779 1780 /* First set the assertion level to ON */ 1781 int k = kIOPMAssertionLevelOn; 1782 CFNumberRef useLevelOnNum = CFNumberCreate(0, kCFNumberIntType, &k); 1783 CFDictionarySetValue(assertion->props, kIOPMAssertionLevelKey, useLevelOnNum); 1784 CFRelease(useLevelOnNum); 1785 1786 *return_code = doSetProperties(callerPID, *assertion_id, assertionProperties); 1787 create_new = false; 1788 } while (false); 1789 1790 if (create_new) { 1791 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertionUserIsActive); 1792 1793 *return_code = doCreate(callerPID, assertionProperties, (IOPMAssertionID *)assertion_id, NULL); 1794 if ((*return_code == kIOReturnSuccess) && 1795 (lookupAssertion(callerPID, *assertion_id, &assertion) == kIOReturnSuccess)) { 1796 assertion->state |= kAssertionTimeoutIsSystemTimer; 1797 } 1798 1799 } 1800 1801#if !TARGET_OS_EMBEDDED 1802 if (*return_code == kIOReturnSuccess) 1803 updateAppSleepStates(processInfoGet(callerPID), disableAppSleep, NULL); 1804#endif 1805 1806exit: 1807 1808 1809 if (assertionProperties) 1810 CFRelease(assertionProperties); 1811 1812 vm_deallocate(mach_task_self(), props, propsCnt); 1813 return KERN_SUCCESS; 1814} 1815 1816kern_return_t _io_pm_declare_network_client_active ( 1817 mach_port_t server __unused, 1818 audit_token_t token, 1819 vm_offset_t props, 1820 mach_msg_type_number_t propsCnt, 1821 int *assertion_id, 1822 int *disableAppSleep, 1823 int *return_code) 1824{ 1825 1826 bool create_new = true; 1827 pid_t callerPID = -1; 1828 CFTimeInterval idleSleepTimerSecs = 0; 1829 IOReturn ret; 1830 CFDataRef unfolder = NULL; 1831 CFNumberRef idleSleepTimerCF = NULL; 1832 assertion_t * assertion = NULL; 1833 1834 CFMutableDictionaryRef assertionProperties = NULL; 1835 1836 audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &callerPID, NULL, NULL); 1837 1838 *disableAppSleep = 0; 1839 unfolder = CFDataCreateWithBytesNoCopy(0, (const UInt8 *)props, propsCnt, kCFAllocatorNull); 1840 if (unfolder) { 1841 assertionProperties = (CFMutableDictionaryRef) 1842 CFPropertyListCreateWithData(0, unfolder, 1843 kCFPropertyListMutableContainersAndLeaves, 1844 NULL, NULL); 1845 CFRelease(unfolder); 1846 } 1847 1848 if (!assertionProperties) { 1849 *return_code = kIOReturnBadArgument; 1850 goto exit; 1851 } 1852 1853 /* Set the assertion timeout value to idle sleep timer value, if it is not 0 */ 1854 1855 idleSleepTimerSecs = gIdleSleepTimer * 60; /* Convert to secs */ 1856 1857 if (idleSleepTimerSecs) { 1858 idleSleepTimerCF = CFNumberCreate(0, kCFNumberDoubleType, &idleSleepTimerSecs); 1859 CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutKey, idleSleepTimerCF); 1860 CFRelease(idleSleepTimerCF); 1861 1862 CFDictionarySetValue(assertionProperties, kIOPMAssertionTimeoutActionKey, kIOPMAssertionTimeoutActionRelease); 1863 } 1864 1865 /* Check if this is a repeat call on previously returned assertion id */ 1866 do { 1867 if (assertion_id == NULL || *assertion_id == kIOPMNullAssertionID) 1868 break; 1869 1870 ret = lookupAssertion(callerPID, *assertion_id, &assertion); 1871 if ((kIOReturnSuccess != ret) || !assertion) 1872 break; 1873 1874 if (assertion->kassert != kNetworkAccessType) 1875 break; 1876 1877 /* Extend the timeout timer of this assertion by idle sleep timer value */ 1878 1879 /* First set the assertion level to ON */ 1880 int k = kIOPMAssertionLevelOn; 1881 CFNumberRef useLevelOnNum = CFNumberCreate(0, kCFNumberIntType, &k); 1882 CFDictionarySetValue(assertion->props, kIOPMAssertionLevelKey, useLevelOnNum); 1883 CFRelease(useLevelOnNum); 1884 1885 *return_code = doSetProperties(callerPID, *assertion_id, assertionProperties); 1886 create_new = false; 1887 } while (false); 1888 1889 if (create_new) { 1890 CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertNetworkClientActive); 1891 1892 *return_code = doCreate(callerPID, assertionProperties, (IOPMAssertionID *)assertion_id, NULL); 1893 if ((*return_code == kIOReturnSuccess) && 1894 (lookupAssertion(callerPID, *assertion_id, &assertion) == kIOReturnSuccess)) { 1895 assertion->state |= kAssertionTimeoutIsSystemTimer; 1896 } 1897 1898 } 1899 1900#if !TARGET_OS_EMBEDDED 1901 if (*return_code == kIOReturnSuccess) 1902 updateAppSleepStates(processInfoGet(callerPID), disableAppSleep, NULL); 1903#endif 1904 1905exit: 1906 if (assertionProperties) 1907 CFRelease(assertionProperties); 1908 1909 vm_deallocate(mach_task_self(), props, propsCnt); 1910 return KERN_SUCCESS; 1911} 1912 1913 1914 1915int do_assertion_notify(pid_t callerPID, string_t name, int req_type) 1916{ 1917 1918 ProcessInfo *pinfo = NULL; 1919 bool mod = false; 1920 int return_code = kIOReturnSuccess; 1921 1922 if (req_type == kIOPMNotifyRegister) 1923 { 1924 // Create a dispatch handler for process exit, if there isn't one 1925 if ( !(pinfo = processInfoRetain(callerPID)) ) { 1926 pinfo = processInfoCreate(callerPID); 1927 if (!pinfo) { 1928 return_code = kIOReturnNoMemory; 1929 goto exit; 1930 } 1931 } 1932 } 1933 else { 1934 if ( !(pinfo = processInfoGet(callerPID)) ) { 1935 return_code = kIOReturnBadArgument; 1936 goto exit; 1937 } 1938 } 1939 1940 if (!strncmp(name, kIOPMAssertionsAnyChangedNotifyString, sizeof(kIOPMAssertionsAnyChangedNotifyString))) 1941 { 1942 if (req_type == kIOPMNotifyRegister && pinfo->anychange == false) { 1943 pinfo->anychange = true; 1944 mod = true; 1945 gAnyChange++; 1946 } 1947 else if (req_type == kIOPMNotifyDeRegister && pinfo->anychange == true) { 1948 pinfo->anychange = false; 1949 gAnyChange--; 1950 processInfoRelease(callerPID); 1951 } 1952 } 1953 else if (!strncmp(name, kIOPMAssertionsChangedNotifyString, sizeof(kIOPMAssertionsChangedNotifyString))) 1954 { 1955 if (req_type == kIOPMNotifyRegister && pinfo->aggchange == false) { 1956 pinfo->aggchange = true; 1957 mod = true; 1958 gAggChange++; 1959 } 1960 else if (req_type == kIOPMNotifyDeRegister && pinfo->aggchange == true) { 1961 pinfo->aggchange = false; 1962 gAggChange--; 1963 processInfoRelease(callerPID); 1964 } 1965 } 1966 else if (!strncmp(name, kIOPMAssertionTimedOutNotifyString, sizeof(kIOPMAssertionTimedOutNotifyString))) 1967 { 1968 if (req_type == kIOPMNotifyRegister && pinfo->timeoutchange == false) { 1969 pinfo->timeoutchange = true; 1970 mod = true; 1971 gTimeoutChange++; 1972 } 1973 else if (req_type == kIOPMNotifyDeRegister && pinfo->timeoutchange == true) { 1974 pinfo->timeoutchange = false; 1975 gTimeoutChange--; 1976 processInfoRelease(callerPID); 1977 } 1978 } 1979 else { 1980 return_code = kIOReturnBadArgument; 1981 } 1982 1983 if (!mod && (req_type == kIOPMNotifyRegister)) 1984 processInfoRelease(callerPID); 1985 1986exit: 1987 return return_code; 1988 1989} 1990 1991static void releaseStatsBuf(ProcessInfo *pinfo) 1992{ 1993 1994 if (pinfo->reportBuf == NULL) return; 1995 1996 memset(pinfo->stats, 0, sizeof(pinfo->stats)); 1997 free(pinfo->reportBuf); 1998 pinfo->reportBuf = NULL; 1999 processInfoRelease(pinfo->pid); 2000 2001} 2002 2003 2004static void allocStatsBuf(ProcessInfo *pinfo) 2005{ 2006 kerAssertionEffect i; 2007 2008 if (gActivityAggCnt == 0) return; 2009 if (pinfo->reportBuf) return; 2010 2011 size_t nbytes = SIMPLEARRAY_BUFSIZE(kMaxEffectStats); 2012 pinfo->reportBuf = malloc(nbytes); 2013 2014 if (pinfo->reportBuf) { 2015 SIMPLEARRAY_INIT(kMaxEffectStats, pinfo->reportBuf, nbytes, getpid(), 2016 pinfo->pid, /* Channel ID */ 2017 kIOReportCategoryPower); 2018 for (i=0; i < kMaxEffectStats; i++) { 2019 SIMPLEARRAY_SETVALUE(pinfo->reportBuf, i, 0); 2020 } 2021 memset(pinfo->stats, 0, sizeof(pinfo->stats)); 2022 processInfoRetain(pinfo->pid); 2023 } 2024} 2025 2026void setAssertionActivityAggregate(int value) 2027{ 2028 kerAssertionType i; 2029 assertionType_t *assertType = NULL; 2030 CFIndex j, cnt; 2031 ProcessInfo **procs = NULL; 2032 2033 if (value) { 2034 if (gActivityAggCnt++ == 0) { 2035 cnt = CFDictionaryGetCount(gProcessDict); 2036 procs = malloc(cnt*(sizeof(procs))); 2037 if (!procs) return; 2038 2039 memset(procs, 0, cnt*(sizeof(procs))); 2040 CFDictionaryGetKeysAndValues(gProcessDict, NULL, (const void **)procs); 2041 for (j = 0; (j < cnt) && (procs[j] != NULL); j++) { 2042 allocStatsBuf(procs[j]); 2043 } 2044 free(procs); 2045 2046 for (i=0; i < kIOPMNumAssertionTypes; i++) 2047 { 2048 assertType = &gAssertionTypes[i]; 2049 2050 if (assertType->effectIdx >= kMaxEffectStats) 2051 continue; 2052 applyToAllAssertionsSync(assertType, false, ^(assertion_t *assertion) 2053 { 2054 updateAppStats(assertion, kAssertionOpRaise); 2055 }); 2056 2057 } 2058 } 2059 } 2060 else if ((gActivityAggCnt) && (--gActivityAggCnt == 0)) { 2061 cnt = CFDictionaryGetCount(gProcessDict); 2062 procs = malloc(cnt*(sizeof(procs))); 2063 if (!procs) return; 2064 2065 memset(procs, 0, cnt*(sizeof(procs))); 2066 CFDictionaryGetKeysAndValues(gProcessDict, NULL, (const void **)procs); 2067 for (j = 0; (j < cnt) && (procs[j] != NULL); j++) { 2068 releaseStatsBuf(procs[j]); 2069 } 2070 free(procs); 2071 2072 for (i=0; i < kIOPMNumAssertionTypes; i++) 2073 { 2074 assertType = &gAssertionTypes[i]; 2075 2076 if (assertType->effectIdx >= kMaxEffectStats) 2077 continue; 2078 applyToAllAssertionsSync(assertType, true, ^(assertion_t *assertion) 2079 { 2080 assertion->state &= ~kAssertionStateAddsToProcStats; 2081 }); 2082 } 2083 2084 } 2085 2086} 2087 2088 2089kern_return_t _io_pm_assertion_notify ( 2090 mach_port_t server __unused, 2091 audit_token_t token, 2092 string_t name, 2093 int req_type, 2094 int *return_code) 2095{ 2096 pid_t callerPID = -1; 2097 uid_t callerUID = -1; 2098 gid_t callerGID = -1; 2099 2100 *return_code = kIOReturnSuccess; 2101 audit_token_to_au32(token, NULL, NULL, NULL, &callerUID, &callerGID, &callerPID, NULL, NULL); 2102 if ( !(callerIsRoot(callerUID) || callerIsAdmin(callerUID, callerGID))) 2103 { 2104 *return_code = kIOReturnNotPrivileged; 2105 goto exit; 2106 } 2107 2108 if (req_type != kIOPMNotifyRegister && req_type != kIOPMNotifyDeRegister) 2109 { 2110 *return_code = kIOReturnNoMemory; 2111 goto exit; 2112 } 2113 2114 *return_code = do_assertion_notify(callerPID, name, req_type); 2115 2116exit: 2117 return KERN_SUCCESS; 2118} 2119 2120uint8_t getAssertionLevel(kerAssertionType idx) 2121{ 2122 return ((aggregate_assertions & (1 << idx)) ? 1:0); 2123} 2124 2125void setAggregateLevel(kerAssertionType idx, uint8_t val) 2126{ 2127 if (val) 2128 aggregate_assertions |= (1 << idx); 2129 else 2130 aggregate_assertions &= ~(1<<idx); 2131} 2132 2133uint32_t getKerAssertionBits( ) 2134{ 2135 return kerAssertionBits; 2136} 2137 2138void insertInactiveAssertion(assertion_t *assertion, assertionType_t *assertType) 2139{ 2140 LIST_INSERT_HEAD(&assertType->inactive, assertion, link); 2141 assertion->state &= ~kAssertionStateTimed; 2142 assertion->state |= kAssertionStateInactive; 2143} 2144 2145void removeInactiveAssertion(assertion_t *assertion, assertionType_t *assertType) 2146{ 2147 LIST_REMOVE(assertion, link); 2148 assertion->state &= ~kAssertionStateInactive; 2149} 2150 2151void insertActiveAssertion(assertion_t *assertion, assertionType_t *assertType) 2152{ 2153 LIST_INSERT_HEAD(&assertType->active, assertion, link); 2154 assertion->state &= ~(kAssertionStateTimed|kAssertionStateInactive); 2155 2156 if ( (assertType->flags & kAssertionTypeNotValidOnBatt) && 2157 (assertion->state & kAssertionStateValidOnBatt) ) 2158 assertType->validOnBattCount++; 2159 2160 if (assertion->state & kAssertionLidStateModifier) 2161 assertType->lidSleepCount++; 2162 2163 updateAppStats(assertion, kAssertionOpRaise); 2164 schedDisableAppSleep(assertion); 2165} 2166 2167void removeActiveAssertion(assertion_t *assertion, assertionType_t *assertType) 2168{ 2169 LIST_REMOVE(assertion, link); 2170 2171 if ( (assertion->state & kAssertionStateValidOnBatt) && assertType->validOnBattCount) 2172 assertType->validOnBattCount--; 2173 2174 if ( (assertion->state & kAssertionLidStateModifier) && assertType->lidSleepCount) 2175 assertType->lidSleepCount--; 2176 2177 updateAppStats(assertion, kAssertionOpRelease); 2178 schedEnableAppSleep(assertion); 2179} 2180 2181 2182void resetAssertionTimer(assertionType_t *assertType) 2183{ 2184 uint64_t currTime ; 2185 assertion_t *nextAssertion = NULL; 2186 2187 nextAssertion = LIST_FIRST(&assertType->activeTimed); 2188 if (!nextAssertion) return; 2189 2190 currTime = getMonotonicTime(); 2191 2192 if (nextAssertion->timeout <= currTime) { 2193 CFRunLoopPerformBlock(_getPMRunLoop(), kCFRunLoopDefaultMode, ^{ handleAssertionTimeout(assertType); }); 2194 CFRunLoopWakeUp(_getPMRunLoop()); 2195 } 2196 else { 2197 dispatch_suspend(assertType->timer); 2198 2199 dispatch_source_set_timer(assertType->timer, 2200 dispatch_time(DISPATCH_TIME_NOW, (nextAssertion->timeout-currTime)*NSEC_PER_SEC), 2201 DISPATCH_TIME_FOREVER, 0); 2202 dispatch_resume(assertType->timer); 2203 } 2204 2205} 2206 2207 2208static void releaseAssertionMemory(assertion_t *assertion, assertLogAction logAction) 2209{ 2210 int idx = INDEX_FROM_ID(assertion->assertionId); 2211 assertion_t *tmp_a = NULL; 2212 2213 if ( (idx < 0) || (idx >= kMaxAssertions) || 2214 (CFDictionaryGetValueIfPresent(gAssertionsArray, 2215 (uintptr_t)idx, (const void **)&tmp_a) == false) || (tmp_a != assertion) ) { 2216#ifdef DEBUG 2217 abort(); 2218#endif 2219 return; // This is an error 2220 } 2221 2222 assertion->retainCnt = 0; 2223 logAssertionEvent(logAction, assertion); 2224 CFDictionaryRemoveValue(gAssertionsArray, (uintptr_t)idx); 2225 if (assertion->props) CFRelease(assertion->props); 2226 2227 2228 processInfoRelease(assertion->pinfo->pid); 2229 free(assertion); 2230} 2231 2232void handleAssertionTimeout(assertionType_t *assertType) 2233{ 2234 assertion_t *assertion; 2235 CFDateRef dateNow = NULL; 2236 uint64_t currtime = getMonotonicTime( ); 2237 uint32_t timedoutCnt = 0; 2238 CFStringRef timeoutAction = NULL; 2239 bool displayProxy = false; 2240 2241 while( (assertion = LIST_FIRST(&assertType->activeTimed)) ) 2242 { 2243 if (assertion->timeout > currtime) { 2244 assertion = NULL; 2245 break; 2246 } 2247 timedoutCnt++; 2248 2249 LIST_REMOVE(assertion, link); 2250 assertion->state &= ~kAssertionStateTimed; 2251 2252 if ( (assertion->state & kAssertionStateValidOnBatt) && assertType->validOnBattCount) 2253 assertType->validOnBattCount--; 2254 2255 if ( (assertion->state & kAssertionLidStateModifier) && assertType->lidSleepCount) 2256 assertType->lidSleepCount--; 2257 2258 updateAppStats(assertion, kAssertionOpRelease); 2259 schedEnableAppSleep( assertion ); 2260 2261 if ((dateNow = CFDateCreate(0, CFAbsoluteTimeGetCurrent()))) { 2262 CFDictionarySetValue(assertion->props, kIOPMAssertionTimedOutDateKey, dateNow); 2263 CFRelease(dateNow); 2264 } 2265 2266 2267 if ( (assertion->kassert == kPreventDisplaySleepType) && 2268 (assertion->pinfo->pid != getpid())) 2269 displayProxy = true; 2270 2271 timeoutAction = CFDictionaryGetValue(assertion->props, kIOPMAssertionTimeoutActionKey); 2272 if (isA_CFString(timeoutAction) && CFEqual(kIOPMAssertionTimeoutActionRelease, timeoutAction)) 2273 { 2274 releaseAssertionMemory(assertion, kATimeoutLog); 2275 } 2276 else /* Default timeout action is to turn off */ 2277 { 2278 logAssertionEvent(kATimeoutLog, assertion); 2279 2280 // Leave this in the inactive assertions list 2281 insertInactiveAssertion(assertion, assertType); 2282 if (isA_CFString(timeoutAction) && CFEqual(kIOPMAssertionTimeoutActionKillProcess, timeoutAction)) 2283 { 2284 kill(assertion->pinfo->pid, SIGTERM); 2285 } 2286 2287 } 2288 2289 } 2290 2291 if ( !timedoutCnt ) return; 2292 2293 resetAssertionTimer(assertType); 2294 2295 if (displayProxy) delayDisplayTurnOff( ); 2296 2297 if (assertType->handler) 2298 (*assertType->handler)(assertType, kAssertionOpRelease); 2299 2300 logASLAssertionsAggregate(); 2301 if (gTimeoutChange) notify_post( kIOPMAssertionTimedOutNotifyString ); 2302 if (gAnyChange) notify_post( kIOPMAssertionsAnyChangedNotifyString ); 2303 2304} 2305 2306void removeTimedAssertion(assertion_t *assertion, assertionType_t *assertType, bool updateTimer) 2307{ 2308 bool isTheFirstOne = false; 2309 2310 CFDictionaryRemoveValue(assertion->props, kIOPMAssertionTimeoutTimeLeftKey); 2311 if (LIST_FIRST(&assertType->activeTimed) == assertion) { 2312 isTheFirstOne = true; 2313 } 2314 LIST_REMOVE(assertion, link); 2315 assertion->state &= ~kAssertionStateTimed; 2316 2317 if ( (assertion->state & kAssertionStateValidOnBatt) && assertType->validOnBattCount) 2318 assertType->validOnBattCount--; 2319 2320 if ( (assertion->state & kAssertionLidStateModifier) && assertType->lidSleepCount) 2321 assertType->lidSleepCount--; 2322 2323 updateAppStats(assertion, kAssertionOpRelease); 2324 schedEnableAppSleep(assertion); 2325 2326 if (isTheFirstOne && updateTimer) resetAssertionTimer(assertType); 2327 2328} 2329 2330void updateAssertionTimer(assertionType_t *assertType) 2331{ 2332 uint64_t currTime; 2333 assertion_t *assertion = NULL; 2334 2335 if ((assertion = LIST_FIRST(&assertType->activeTimed)) == NULL) return; 2336 2337 /* Update/create the dispatch timer. */ 2338 if (assertType->timer == NULL) { 2339 assertType->timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); 2340 2341 dispatch_source_set_event_handler(assertType->timer, ^{ 2342 handleAssertionTimeout(assertType); 2343 }); 2344 2345 dispatch_source_set_cancel_handler(assertType->timer, ^{ 2346 dispatch_release(assertType->timer); 2347 }); 2348 2349 } 2350 else { 2351 dispatch_suspend(assertType->timer); 2352 } 2353 currTime = getMonotonicTime(); 2354 2355 2356 if (assertion->timeout <= currTime) { 2357 /* This has already timed out. */ 2358 dispatch_resume(assertType->timer); 2359 CFRunLoopPerformBlock(_getPMRunLoop(), kCFRunLoopDefaultMode, ^{ handleAssertionTimeout(assertType); }); 2360 CFRunLoopWakeUp(_getPMRunLoop()); 2361 } 2362 else { 2363 dispatch_source_set_timer(assertType->timer, 2364 dispatch_time(DISPATCH_TIME_NOW, (assertion->timeout-currTime)*NSEC_PER_SEC), 2365 DISPATCH_TIME_FOREVER, 0); 2366 dispatch_resume(assertType->timer); 2367 } 2368 2369 2370} 2371 2372/* Inserts assertion into activeTimed list, sorted by timeout */ 2373static void insertByTimeout(assertion_t *assertion, assertionType_t *assertType) 2374{ 2375 assertion_t *a, *prev; 2376 CFNumberRef timeLeftCF = NULL; 2377 uint64_t currTime, timeLeft; 2378 CFDateRef updateDate = NULL; 2379 2380 currTime = getMonotonicTime(); 2381 if (assertion->timeout > currTime) { 2382 /* Update timeout time left property */ 2383 timeLeft = (assertion->timeout-currTime); 2384 int timeLeft32 = (int)timeLeft; 2385 timeLeftCF = CFNumberCreate(0, kCFNumberIntType, &timeLeft32); 2386 2387 if (timeLeftCF) { 2388 CFDictionarySetValue(assertion->props, kIOPMAssertionTimeoutTimeLeftKey, timeLeftCF); 2389 CFRelease(timeLeftCF); 2390 } 2391 2392 updateDate = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); 2393 if (updateDate) { 2394 CFDictionarySetValue(assertion->props, kIOPMAssertionTimeoutUpdateTimeKey, updateDate); 2395 CFRelease(updateDate); 2396 } 2397 } 2398 2399 if (LIST_EMPTY(&assertType->activeTimed) ) { 2400 LIST_INSERT_HEAD(&assertType->activeTimed, assertion, link); 2401 } 2402 else { 2403 LIST_FOREACH(a, &assertType->activeTimed, link) 2404 { 2405 prev = a; 2406 if (a->timeout > assertion->timeout) 2407 break; 2408 } 2409 if (a) 2410 LIST_INSERT_BEFORE(a, assertion, link); 2411 else 2412 LIST_INSERT_AFTER(prev, assertion, link); 2413 } 2414 2415} 2416 2417void insertTimedAssertion(assertion_t *assertion, assertionType_t *assertType, bool updateTimer) 2418{ 2419 insertByTimeout(assertion, assertType); 2420 2421 assertion->state |= kAssertionStateTimed; 2422 if ( (assertType->flags & kAssertionTypeNotValidOnBatt) && 2423 (assertion->state & kAssertionStateValidOnBatt) ) 2424 assertType->validOnBattCount++; 2425 2426 if (assertion->state & kAssertionLidStateModifier) 2427 assertType->lidSleepCount++; 2428 2429 updateAppStats(assertion, kAssertionOpRaise); 2430 schedDisableAppSleep( assertion ); 2431 /* 2432 * If this assertion is not the one with earliest timeout, 2433 * there is nothing to do. 2434 */ 2435 if (LIST_FIRST(&assertType->activeTimed) != assertion) 2436 return; 2437 2438 if (updateTimer) updateAssertionTimer(assertType); 2439 2440 return; 2441} 2442 2443 2444static void releaseAssertion(assertion_t *assertion, bool callHandler) 2445{ 2446 assertionType_t *assertType; 2447 2448 assertType = &gAssertionTypes[assertion->kassert]; 2449 2450 if ( (assertion->kassert == kPreventDisplaySleepType) && 2451 (assertion->pinfo->pid != getpid())) 2452 delayDisplayTurnOff( ); 2453 if (assertion->state & kAssertionStateTimed) 2454 removeTimedAssertion(assertion, assertType, true); 2455 else if (assertion->state & kAssertionStateInactive) 2456 removeInactiveAssertion(assertion, assertType); 2457 else 2458 removeActiveAssertion(assertion, assertType); 2459 2460 if (!callHandler) return; 2461 2462 if (assertType->handler) 2463 (*assertType->handler)(assertType, kAssertionOpRelease); 2464 2465 2466} 2467 2468static IOReturn doRelease(pid_t pid, IOPMAssertionID id) 2469{ 2470 IOReturn ret; 2471 2472 assertion_t *assertion = NULL; 2473 ret = lookupAssertion(pid, id, &assertion); 2474 if ((kIOReturnSuccess != ret)) { 2475 return ret; 2476 } 2477 2478 if (assertion->retainCnt) 2479 assertion->retainCnt--; 2480 2481 if (assertion->retainCnt) { 2482 return kIOReturnSuccess; 2483 } 2484 2485 releaseAssertion(assertion, true); 2486 releaseAssertionMemory(assertion, kAReleaseLog); 2487 2488 if (gAnyChange) notify_post( kIOPMAssertionsAnyChangedNotifyString ); 2489 2490 return kIOReturnSuccess; 2491} 2492 2493 2494__private_extern__ void applyToAllAssertionsSync(assertionType_t *assertType, 2495 bool applyToInactives, void (^performOnAssertion)(assertion_t *)) 2496{ 2497 assertion_t *assertion, *nextAssertion; 2498 2499 assertion = LIST_FIRST(&assertType->active); 2500 while( assertion ) 2501 { 2502 nextAssertion = LIST_NEXT(assertion, link); 2503 performOnAssertion(assertion); 2504 assertion = nextAssertion; 2505 } 2506 2507 assertion = LIST_FIRST(&assertType->activeTimed); 2508 while( assertion ) 2509 { 2510 nextAssertion = LIST_NEXT(assertion, link); 2511 performOnAssertion(assertion); 2512 assertion = nextAssertion; 2513 } 2514 2515 if ( !applyToInactives) return; 2516 2517 assertion = LIST_FIRST(&assertType->inactive); 2518 while( assertion ) 2519 { 2520 nextAssertion = LIST_NEXT(assertion, link); 2521 performOnAssertion(assertion); 2522 assertion = nextAssertion; 2523 } 2524 2525} 2526 2527__private_extern__ void HandleProcessExit(pid_t deadPID) 2528{ 2529 int i; 2530 assertionType_t *assertType = NULL; 2531 assertion_t *assertion = NULL; 2532 __block LIST_HEAD(, assertion) list = LIST_HEAD_INITIALIZER(list); /* list of assertions released */ 2533 2534 do_assertion_notify(deadPID, kIOPMAssertionsAnyChangedNotifyString, kIOPMNotifyDeRegister); 2535 do_assertion_notify(deadPID, kIOPMAssertionTimedOutNotifyString, kIOPMNotifyDeRegister); 2536 do_assertion_notify(deadPID, kIOPMAssertionsChangedNotifyString, kIOPMNotifyDeRegister); 2537 2538 /* Go thru each assertion type and release all assertion from its lists */ 2539 for (i=0; i < kIOPMNumAssertionTypes; i++) 2540 { 2541 assertType = &gAssertionTypes[i]; 2542 2543 applyToAllAssertionsSync(assertType, true, ^(assertion_t *assertion) 2544 { 2545 if (assertion->pinfo->pid == deadPID) { 2546 releaseAssertion(assertion, false); 2547 LIST_INSERT_HEAD(&list, assertion, link); 2548 } 2549 }); 2550 2551 if (assertType->handler) 2552 (*assertType->handler)(assertType, kAssertionOpRelease); 2553 2554 /* Release memory after calling the handler to get proper aggregate_assertions value into log */ 2555 while( (assertion = LIST_FIRST(&list)) ) 2556 { 2557 LIST_REMOVE(assertion, link); 2558 releaseAssertionMemory(assertion, kAClientDeathLog); 2559 } 2560 2561 } 2562 if (gAnyChange) notify_post( kIOPMAssertionsAnyChangedNotifyString ); 2563 2564 2565} 2566 2567 2568static int getAssertionTypeIndex(CFStringRef type) 2569{ 2570 int idx = -1; 2571 CFNumberRef numRef = NULL; 2572 2573 if (!isA_CFString(type)) 2574 return -1; 2575 2576 numRef = CFDictionaryGetValue(gUserAssertionTypesDict, type); 2577 if (isA_CFNumber(numRef)) 2578 CFNumberGetValue(numRef, kCFNumberIntType, &idx); 2579 2580 if (idx < 0 || idx >= kIOPMNumAssertionTypes) 2581 return -1; 2582 2583 return idx; 2584} 2585static void forwardPropertiesToAssertion(const void *key, const void *value, void *context) 2586{ 2587 assertion_t *assertion = (assertion_t *)context; 2588 assertionType_t *assertType = NULL; 2589 CFTimeInterval timeout = 0; 2590 int level; 2591 2592 if (!isA_CFString(key)) 2593 return; /* Key has to be a string */ 2594 2595 2596 assertType = &gAssertionTypes[assertion->kassert]; 2597 if (CFEqual(key, kIOPMAssertionLevelKey)) { 2598 if (!isA_CFNumber(value)) return; 2599 CFNumberGetValue(value, kCFNumberIntType, &level); 2600 if ( (assertion->state & kAssertionStateInactive) && (level == kIOPMAssertionLevelOn) ) 2601 { 2602 assertion->state &= ~kAssertionStateInactive; 2603 assertion->mods |= kAssertionModLevel; 2604 } 2605 else if ( !(assertion->state & kAssertionStateInactive) && (level == kIOPMAssertionLevelOff) ) 2606 { 2607 assertion->state |= kAssertionStateInactive; 2608 assertion->mods |= kAssertionModLevel; 2609 } 2610 } 2611 else if (CFEqual(key, kIOPMAssertionTimeoutKey)) { 2612 if (!isA_CFNumber(value)) return; 2613 CFNumberGetValue(value, kCFNumberDoubleType, &timeout); 2614 2615 if (assertType->flags & kAssertionTypeAutoTimed) { 2616 /* Restrict timeout to a max value of 'autoTimeout' */ 2617 if (!timeout || (timeout > assertType->autoTimeout)) 2618 timeout = assertType->autoTimeout; 2619 } 2620 2621 if (timeout) { 2622 assertion->timeout = (uint64_t)timeout + getMonotonicTime(); // Absolute time at which assertion expires 2623 } 2624 else { 2625 assertion->timeout = 0; 2626 } 2627 2628 /* Setting a timeout makes an inactive assertion active again */ 2629 if (assertion->state & kAssertionStateInactive) { 2630 assertion->state &= ~kAssertionStateInactive; 2631 assertion->mods |= kAssertionModLevel; 2632 } 2633 else { 2634 assertion->mods |= kAssertionModTimer; 2635 } 2636 } 2637 else if (CFEqual(key, kIOPMAssertionAppliesToLimitedPowerKey)) { 2638 if (!isA_CFBoolean(value)) return; 2639 if ((assertType->flags & kAssertionTypeNotValidOnBatt) == 0) return; 2640 if ((value == kCFBooleanTrue) && !(assertion->state & kAssertionStateValidOnBatt)) 2641 { 2642 assertType->validOnBattCount++; 2643 assertion->state |= kAssertionStateValidOnBatt; 2644 assertion->mods |= kAssertionModPowerConstraint; 2645 } 2646 else if ((value == kCFBooleanFalse) && (assertion->state & kAssertionStateValidOnBatt) ) 2647 { 2648 if (assertType->validOnBattCount) assertType->validOnBattCount--; 2649 assertion->state &= ~kAssertionStateValidOnBatt; 2650 assertion->mods |= kAssertionModPowerConstraint; 2651 } 2652 2653 } 2654 else if ( (assertion->kassert == kDeclareUserActivityType) && CFEqual(key, kIOPMAssertionAppliesOnLidClose)) { 2655 if (!isA_CFBoolean(value)) return; 2656 if ((value == kCFBooleanTrue) && !(assertion->state & kAssertionLidStateModifier)) { 2657 assertType->lidSleepCount++; 2658 assertion->state |= kAssertionLidStateModifier; 2659 assertion->mods |= kAssertionModLidState; 2660 } 2661 else if((value == kCFBooleanFalse) && (assertion->state & kAssertionLidStateModifier)) { 2662 if (assertType->lidSleepCount) assertType->lidSleepCount--; 2663 assertion->state &= ~kAssertionLidStateModifier; 2664 assertion->mods |= kAssertionModLidState; 2665 } 2666 } 2667 else if (CFEqual(key, kIOPMAssertionTypeKey)) { 2668 /* Assertion type can't be modified */ 2669 return; 2670 } 2671 2672 CFDictionarySetValue(assertion->props, key, value); 2673 2674 2675} 2676 2677static IOReturn doSetProperties(pid_t pid, 2678 IOPMAssertionID id, 2679 CFDictionaryRef inProps) 2680{ 2681 assertion_t *assertion = NULL; 2682 assertionType_t *assertType; 2683 uint32_t oldState; 2684 2685 IOReturn ret; 2686 2687 // doSetProperties doesn't handle retain()/release() count. 2688 // Callers should use IOPMAssertionRetain() or IOPMAssertionRelease(). 2689 2690 ret = lookupAssertion(pid, id, &assertion); 2691 2692 if ((kIOReturnSuccess != ret)) { 2693 return ret; 2694 } 2695 2696 assertion->mods = 0; 2697 assertType = &gAssertionTypes[assertion->kassert]; 2698 oldState = assertion->state; 2699 CFDictionaryApplyFunction(inProps, forwardPropertiesToAssertion, 2700 assertion); 2701 2702 2703 2704 if (assertion->mods & kAssertionModLevel) 2705 { 2706 if (assertion->state & kAssertionStateInactive) 2707 { 2708 /* Remove from active or activeTimed list */ 2709 if (oldState & kAssertionStateTimed) 2710 removeTimedAssertion(assertion, assertType, true); 2711 else 2712 removeActiveAssertion(assertion, assertType); 2713 2714 /* Add to inActive list */ 2715 insertInactiveAssertion(assertion, assertType); 2716 2717 if ( (assertion->kassert == kPreventDisplaySleepType) && 2718 (assertion->pinfo->pid != getpid())) 2719 delayDisplayTurnOff( ); 2720 if (assertType->handler) 2721 (*assertType->handler)(assertType, kAssertionOpRelease); 2722 2723 logAssertionEvent(kATurnOffLog, assertion); 2724 } 2725 else 2726 { 2727 /* An inactive assertion is made active now */ 2728 removeInactiveAssertion(assertion, assertType); 2729 CFDictionaryRemoveValue(assertion->props, kIOPMAssertionTimedOutDateKey); 2730 raiseAssertion(assertion); 2731 logAssertionEvent(kATurnOnLog, assertion); 2732 } 2733 if (gAnyChange) notify_post( kIOPMAssertionsAnyChangedNotifyString ); 2734 return kIOReturnSuccess; 2735 } 2736 2737 if (assertion->state & kAssertionStateInactive) 2738 return kIOReturnSuccess; 2739 2740 if (assertion->mods & kAssertionModTimer) 2741 { 2742 /* Remove from active or activeTimed list */ 2743 if (oldState & kAssertionStateTimed) 2744 removeTimedAssertion(assertion, assertType, true); 2745 else 2746 removeActiveAssertion(assertion, assertType); 2747 2748 2749 assertion->createTime = getMonotonicTime(); 2750 2751 if (assertion->timeout != 0) { 2752 insertTimedAssertion(assertion, assertType, true); 2753 } 2754 else { 2755 insertActiveAssertion(assertion, assertType); 2756 } 2757 2758 if (assertion->kassert == kDeclareUserActivityType) 2759 (*assertType->handler)(assertType, kAssertionOpRaise); 2760 2761 if (assertType->handler) 2762 (*assertType->handler)(assertType, kAssertionOpEval); 2763 } 2764 2765 2766 if ( (assertion->mods & kAssertionModPowerConstraint) && 2767 (assertType->handler) ) 2768 { 2769 if (assertion->state & kAssertionStateValidOnBatt) { 2770 (*assertType->handler)(assertType, kAssertionOpRaise); 2771 updateAppStats(assertion, kAssertionOpRaise); 2772 } 2773 else { 2774 (*assertType->handler)(assertType, kAssertionOpRelease); 2775 updateAppStats(assertion, kAssertionOpRelease); 2776 } 2777 2778 } 2779 2780 if ( (assertion->mods & kAssertionModLidState) && 2781 (assertType->handler) ) 2782 { 2783 if (assertion->state & kAssertionLidStateModifier) 2784 (*assertType->handler)(assertType, kAssertionOpRaise); 2785 else 2786 (*assertType->handler)(assertType, kAssertionOpRelease); 2787 2788 } 2789 2790 if (gAnyChange) notify_post( kIOPMAssertionsAnyChangedNotifyString ); 2791 return kIOReturnSuccess; 2792} 2793 2794/* 2795 * Check for active assertions of the specified type and also for active 2796 * assertions of linked types. 2797 * Returns true if active assertions exist either in the specified type or 2798 * in the linked types to the specified type. 2799 */ 2800bool checkForActives(assertionType_t *assertType, bool *existsInThisType ) 2801{ 2802 bool typeActive = false; 2803 bool effectActive = false; 2804 assertionType_t *type = NULL; 2805 assertionEffect_t *effect = NULL; 2806 2807 if (existsInThisType) 2808 *existsInThisType = false; 2809 if (assertType->effectIdx == kNoEffect) 2810 return false; 2811 2812 effect = &gAssertionEffects[assertType->effectIdx]; 2813 2814 LIST_FOREACH(type, &effect->assertTypes, link) { 2815 2816 /* 2817 * Check for active assertions in this assertionType's 'active' & 'activeTimed' lists 2818 */ 2819 if ( (type->flags & kAssertionTypeNotValidOnBatt) && ( _getPowerSource() == kBatteryPowered) ) 2820 typeActive = (type->validOnBattCount > 0); 2821 else 2822 typeActive = (LIST_FIRST(&type->active) || LIST_FIRST(&type->activeTimed)); 2823 2824 effectActive |= typeActive; 2825 if (existsInThisType && (type == assertType) && typeActive) { 2826 *existsInThisType = true; 2827 return true; 2828 } 2829 if (typeActive && !existsInThisType) 2830 return true; 2831 2832 } 2833 2834 return effectActive; 2835} 2836 2837/* 2838 * Checks if there are assertions preventing system going from S0dark to S3. 2839 * Returns true if S3 sleep is prevented. 2840 */ 2841__private_extern__ bool systemBlockedInS0Dark( ) 2842{ 2843 2844 /* PreventSystemSleep assertion and its linked types are the only ones 2845 * that can keep the system in S0dark. 2846 */ 2847 return checkForActives(&gAssertionTypes[kPreventSleepType], NULL); 2848} 2849 2850/* 2851 * Check for active assertions of the specified type. 2852 * Returns true if specified type assertions are active 2853 */ 2854__private_extern__ bool checkForActivesByType(kerAssertionType type) 2855{ 2856 bool activesForTheType = false; 2857 2858 checkForActives(&gAssertionTypes[type], &activesForTheType); 2859 return activesForTheType; 2860} 2861 2862/* 2863 * Check for assertions of the specified type, even if assertion type is disabled. 2864 * Returns true if there any assertions of specified type raised 2865 */ 2866__private_extern__ bool checkForEntriesByType(kerAssertionType type) 2867{ 2868 assertionType_t *assertType = &gAssertionTypes[type]; 2869 2870 if (LIST_FIRST(&assertType->active) || LIST_FIRST(&assertType->activeTimed)) 2871 return true; 2872 2873 return false; 2874} 2875 2876/* Disable the specified assertion type */ 2877__private_extern__ void disableAssertionType(kerAssertionType type) 2878{ 2879 gAssertionTypes[type].disableCnt++; 2880 configAssertionType(type, false); 2881 2882} 2883 2884/* Enablee the specified assertion type */ 2885__private_extern__ void enableAssertionType(kerAssertionType type) 2886{ 2887 if (gAssertionTypes[type].disableCnt) 2888 gAssertionTypes[type].disableCnt--; 2889 2890 configAssertionType(type, false); 2891 2892} 2893 2894__private_extern__ kern_return_t setReservePwrMode(int enable) 2895{ 2896#if TARGET_OS_EMBEDDED 2897 static bool inReservePwrMode = false; 2898 2899 if (enable) { 2900 if (inReservePwrMode) return kIOReturnExclusiveAccess; 2901 2902 disableAssertionType(kPreventIdleType); 2903 disableAssertionType(kDeclareSystemActivityType); 2904 disableAssertionType(kBackgroundTaskType); 2905 disableAssertionType(kPushServiceTaskType); 2906 inReservePwrMode = true; 2907 } 2908 else { 2909 if (!inReservePwrMode) return kIOReturnExclusiveAccess; 2910 2911 enableAssertionType(kPreventIdleType); 2912 enableAssertionType(kDeclareSystemActivityType); 2913 enableAssertionType(kBackgroundTaskType); 2914 enableAssertionType(kPushServiceTaskType); 2915 inReservePwrMode = false; 2916 } 2917 return kIOReturnSuccess; 2918#else 2919 return kIOReturnError; 2920#endif 2921} 2922 2923static inline void updateAggregates(assertionType_t *assertType, bool activesForTheType) 2924{ 2925 if (activesForTheType) { 2926 setAggregateLevel(assertType->kassert, 1 ); 2927 } 2928 else { 2929 if (getAssertionLevel(assertType->kassert) && assertType->globalTimeout) { 2930 resetGlobalTimer(assertType, 0); 2931 } 2932 setAggregateLevel(assertType->kassert, 0 ); 2933 } 2934 2935 userActiveHandlePowerAssertionsChanged(); 2936} 2937 2938static void modifySettings(assertionType_t *assertType, assertionOps op) 2939{ 2940 bool activeExists; 2941 bool activesForTheType = false; 2942 int opVal; 2943 bool assertionLevel = 0; 2944 2945 if (assertType->effectIdx == kNoEffect) 2946 return; 2947 2948 assertionLevel = getAssertionLevel(assertType->kassert); 2949 2950 activeExists = checkForActives(assertType, &activesForTheType); 2951 updateAggregates(assertType, activesForTheType); 2952 2953 2954 if (op == kAssertionOpRaise) { 2955 /* 2956 * if already raised with kernel or if there are no active ones, 2957 * nothing to do 2958 */ 2959 if ( assertionLevel || !activeExists ) 2960 return; 2961 opVal = 1; 2962 } 2963 else if (op == kAssertionOpRelease) { 2964 /* 2965 * If this assertionType is not raised with kernel 2966 * or if there are active ones, nothing to do 2967 */ 2968 if ( !assertionLevel || activeExists) 2969 return; 2970 opVal = 0; 2971 2972 } 2973 else { // op == kAssertionOpEval 2974 if (activeExists) { 2975 if (assertionLevel) 2976 return; 2977 opVal = 1; 2978 } 2979 else { 2980 if (!assertionLevel) 2981 return; 2982 opVal = 0; 2983 } 2984 } 2985 2986 2987 switch(assertType->kassert) { 2988 case kHighPerfType: 2989 overrideSetting( kPMForceHighSpeed, opVal); 2990 break; 2991 2992 case kDeclareSystemActivityType: 2993 // Behaves identical to a PreventIdleSleep 2994 // assertion, except it also backs out of 2995 // idle if possible. 2996 case kBackgroundTaskType: 2997 case kPreventIdleType: 2998 case kNetworkAccessType: 2999 case kInteractivePushServiceType: 3000 case kReservePwrPreventIdleType: 3001 overrideSetting(kPMPreventIdleSleep, opVal); 3002 break; 3003 3004 case kPreventDiskSleepType: 3005 overrideSetting(kPMPreventDiskSleep, opVal); 3006 break; 3007 3008 default: 3009 return; 3010 } 3011 3012 activateSettingOverrides(); 3013 if (gAggChange) notify_post( kIOPMAssertionsChangedNotifyString ); 3014 return; 3015} 3016 3017void handleBatteryAssertions(assertionType_t *assertType, assertionOps op) 3018{ 3019 bool activeExists; 3020 3021 if (op == kAssertionOpEval) 3022 return; // Nothing to evaluate 3023 3024 activeExists = checkForActives(assertType, NULL); 3025 3026 if (op == kAssertionOpRaise) { 3027 /* 3028 * if already raised with kernel or if there are no active ones, 3029 * nothing to do 3030 */ 3031 if ( getAssertionLevel(assertType->kassert) || !activeExists ) 3032 return; 3033 setAggregateLevel(assertType->kassert, 1); 3034 } 3035 else { 3036 /* 3037 * If this assertionType is not raised with kernel 3038 * or if there are active ones, nothing to do 3039 */ 3040 if ( !getAssertionLevel(assertType->kassert) || activeExists) 3041 return; 3042 3043 setAggregateLevel(assertType->kassert, 0); 3044 } 3045 3046 switch(assertType->kassert) { 3047 case kDisableInflowType: 3048 sendSmartBatteryCommand( kSBUCInflowDisable, 3049 op == kAssertionOpRaise ? 1 : 0); 3050 break; 3051 3052 case kInhibitChargeType: 3053 sendSmartBatteryCommand( kSBUCChargeInhibit, 3054 op == kAssertionOpRaise ? 1 : 0); 3055 break; 3056 3057 case kDisableWarningsType: 3058 _setRootDomainProperty( CFSTR("BatteryWarningsDisabled"), kCFBooleanTrue); 3059 break; 3060 3061 default: 3062 break; 3063 } 3064 3065 if (gAggChange) notify_post( kIOPMAssertionsChangedNotifyString ); 3066 return; 3067} 3068 3069void setKernelAssertions(assertionType_t *assertType, assertionOps op) 3070{ 3071 uint32_t assertBit = 0; 3072 bool activeExists, activesForTheType; 3073 3074 if (assertType->effectIdx == kNoEffect) 3075 return; 3076 3077 /* 3078 * active assertions exists if one of the active list is not empty and 3079 * the assertion is not globally disabled. 3080 */ 3081 activeExists = checkForActives(assertType, &activesForTheType); 3082 3083 switch(assertType->kassert) { 3084 3085 case kPushServiceTaskType: 3086#if LOG_SLEEPSERVICES 3087 if ( !activesForTheType && getAssertionLevel(assertType->kassert) ) 3088 logASLMessageSleepServiceTerminated(assertType->forceTimedoutCnt); 3089#endif 3090 assertBit = kIOPMDriverAssertionCPUBit; 3091 break; 3092 3093 case kInteractivePushServiceType: 3094 case kPreventSleepType: 3095 case kBackgroundTaskType: 3096 case kSRPreventSleepType: 3097 case kNetworkAccessType: 3098 assertBit = kIOPMDriverAssertionCPUBit; 3099 break; 3100 3101 case kDeclareUserActivityType: 3102 case kPreventDisplaySleepType: 3103 case kIntPreventDisplaySleepType: 3104 assertBit = kIOPMDriverAssertionPreventDisplaySleepBit; 3105 break; 3106 3107 case kExternalMediaType: 3108 assertBit = kIOPMDriverAssertionExternalMediaMountedBit; 3109 break; 3110 3111 default: 3112 return; 3113 } 3114 3115 updateAggregates(assertType, activesForTheType); 3116 3117 if (op == kAssertionOpRaise) { 3118 3119 if ((assertType->kassert == kDeclareUserActivityType) && activesForTheType) { 3120 if (assertType->lidSleepCount) setClamshellSleepState(1); 3121 sendActivityTickle(); 3122 _unclamp_silent_running(true); 3123 } 3124 3125 /* 3126 * If server-mode power assertion is being raised anew, then we need 3127 * to unclamp SilentRunning through AppleSMC 3128 */ 3129#if !TARGET_OS_EMBEDDED 3130 if ( ((assertType->kassert == kPreventSleepType) || (assertType->kassert == kNetworkAccessType)) 3131 && activesForTheType) 3132 _unclamp_silent_running(true); 3133#endif 3134 /* 3135 * if already raised with kernel or if there are no active ones, 3136 * nothing to do 3137 */ 3138 if ( (kerAssertionBits & assertBit) || !activeExists ) 3139 return; 3140 3141 } 3142 else if (op == kAssertionOpRelease) { 3143 if ((assertType->kassert == kDeclareUserActivityType) && (assertType->lidSleepCount == 0)) 3144 setClamshellSleepState(0); 3145 3146 /* 3147 * If this assertionType is not raised with kernel 3148 * or if there are active ones, nothing to do 3149 */ 3150 if ( !(kerAssertionBits & assertBit) || activeExists) 3151 return; 3152 3153 } 3154 else { // op == kAssertionOpEval 3155 3156#if !TARGET_OS_EMBEDDED 3157 if ( (assertType->kassert == kPreventSleepType) && activesForTheType) 3158 _unclamp_silent_running(true); 3159 3160#endif 3161 if (activeExists && (kerAssertionBits & assertBit)) 3162 return; 3163 else if ( !activeExists && !(kerAssertionBits & assertBit) ) 3164 return; 3165 } 3166 3167 3168 3169 3170 if (activeExists) { 3171 kerAssertionBits |= assertBit; 3172 sendUserAssertionsToKernel(kerAssertionBits); 3173 } 3174 else { 3175 kerAssertionBits &= ~assertBit; 3176 sendUserAssertionsToKernel(kerAssertionBits); 3177 } 3178 if (gAggChange) notify_post( kIOPMAssertionsChangedNotifyString ); 3179} 3180 3181static void enableIdleHandler(assertionType_t *assertType, assertionOps op) 3182{ 3183 static IOPMAssertionID enableIdleId = kIOPMNullAssertionID; 3184 CFMutableDictionaryRef assertionDescription = NULL; 3185 bool activeExists; 3186 3187#if !TARGET_OS_EMBEDDED 3188 return; // Supported for embedded only 3189#endif 3190 3191 if (op == kAssertionOpEval) 3192 return; // Nothing to evaluate 3193 3194 if (assertType->kassert != kEnableIdleType) 3195 return; 3196 3197 activeExists = checkForActives(assertType, NULL); 3198 3199 if (op == kAssertionOpRaise) { 3200 /* Check if this assertType is already raised */ 3201 if ( !activeExists ) 3202 return; 3203 setAggregateLevel(assertType->kassert, 1); 3204 3205 InternalReleaseAssertion(&enableIdleId); 3206 } 3207 else { 3208 3209 /* If not the last one or if this assertType is not raised, nothing to do */ 3210 if ( activeExists ) 3211 return; 3212 setAggregateLevel(assertType->kassert, 0); 3213 3214 assertionDescription = _IOPMAssertionDescriptionCreate( 3215 kIOPMAssertionTypePreventUserIdleSystemSleep, 3216 CFSTR("com.apple.powermanagement.enableIdle"), 3217 NULL, CFSTR("Waiting for Idle Sleep to enabled"), NULL, 0, 0); 3218 3219 InternalCreateAssertion(assertionDescription, &enableIdleId); 3220 3221 CFRelease(assertionDescription); 3222 3223 3224 3225 } 3226 3227 if (gAggChange) notify_post( kIOPMAssertionsChangedNotifyString ); 3228} 3229 3230#if TCPKEEPALIVE 3231static void displayWakeHandler(assertionType_t *assertType, assertionOps op) 3232{ 3233 bool activesForTheType = false; 3234 bool activeExists; 3235 uint64_t level = 0; 3236 bool assertionLevel = 0; 3237 io_connect_t connect = IO_OBJECT_NULL; 3238 3239 if (assertType->kassert != kTicklessDisplayWakeType) 3240 return; 3241 3242 assertionLevel = getAssertionLevel(assertType->kassert); 3243 activeExists = checkForActives(assertType, &activesForTheType); 3244 updateAggregates(assertType, activesForTheType); 3245 3246 if (op == kAssertionOpRaise) { 3247 if ( !activeExists ) return; 3248 level = 1; 3249 } 3250 else if (op == kAssertionOpRelease) { 3251 if ( activeExists ) return; 3252 level = 0; 3253 } 3254 else { // op == kAssertionOpEval 3255 if (activeExists) { 3256 if (assertionLevel) 3257 return; 3258 level = 1; 3259 } 3260 else { 3261 if (!assertionLevel) 3262 return; 3263 level = 0; 3264 } 3265 } 3266 3267 if ( (connect = getRootDomainConnect()) == IO_OBJECT_NULL) 3268 return; 3269 3270 if (level && isA_DarkWakeState() ) { 3271 set_NotificationDisplayWake( ); 3272 } 3273 3274 IOConnectCallMethod(connect, kPMSetDisplayPowerOn, 3275 &level, 1, 3276 NULL, 0, NULL, 3277 NULL, NULL, NULL); 3278 3279 if (level && (gDarkWakeNetworkAssertion != kIOPMNullAssertionID)) { 3280 // Release n/w proxy, if it exists. 3281 // XXX: This is not a right place to release this, but leaving it here 3282 // for now, as this is the only case of releasing an assertion when another 3283 // is created 3284 dispatch_async(dispatch_get_main_queue(), ^{ 3285 doRelease(getpid(), gDarkWakeNetworkAssertion); 3286 gDarkWakeNetworkAssertion = kIOPMNullAssertionID; 3287 }); 3288 } 3289 if (gAggChange) notify_post( kIOPMAssertionsChangedNotifyString ); 3290} 3291#endif 3292 3293void enforceAssertionTypeTimeCap(assertionType_t *assertType) 3294{ 3295 assertion_t *assertion = NULL; 3296 3297 if ((assertType->flags & kAssertionTypeGloballyTimed) == 0) 3298 return; 3299 assertType->forceTimedoutCnt = 0; 3300 /* Move all active assertions to inactive mode */ 3301 while( (assertion = LIST_FIRST(&assertType->active)) ) 3302 { 3303 removeActiveAssertion(assertion, assertType); 3304 insertInactiveAssertion(assertion, assertType); 3305 assertType->forceTimedoutCnt++; 3306 logAssertionEvent(kACapExpiryLog, assertion); 3307 mt2RecordAssertionEvent(kAssertionOpGlobalTimeout, assertion); 3308 } 3309 3310 /* Timeout all timed assertions */ 3311 while( (assertion = LIST_FIRST(&assertType->activeTimed)) ) 3312 { 3313 LIST_REMOVE(assertion, link); 3314 assertion->state &= ~kAssertionStateTimed; 3315 3316 updateAppStats(assertion, kAssertionOpRelease); 3317 schedEnableAppSleep( assertion ); 3318 3319 insertInactiveAssertion(assertion, assertType); 3320 assertType->forceTimedoutCnt++; 3321 logAssertionEvent(kACapExpiryLog, assertion); 3322 mt2RecordAssertionEvent(kAssertionOpGlobalTimeout, assertion); 3323 } 3324 3325 resetAssertionTimer(assertType); 3326 3327 if (assertType->handler) 3328 (*assertType->handler)(assertType, kAssertionOpRelease); 3329 3330 if (assertType->forceTimedoutCnt == 0) 3331 logASLMessageSleepServiceTerminated(0); 3332 3333 logASLAssertionsAggregate(); 3334} 3335 3336void resetGlobalTimer(assertionType_t *assertType, uint64_t timeout) 3337{ 3338 3339 if ((assertType->flags & kAssertionTypeGloballyTimed) == 0) 3340 return; 3341 assertType->globalTimeout = timeout; 3342 if (assertType->globalTimeout == 0) { 3343 if ( assertType->globalTimer) 3344 dispatch_source_cancel(assertType->globalTimer); 3345 return; 3346 } 3347 3348 if (assertType->globalTimer == NULL) { 3349 assertType->globalTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); 3350 3351 dispatch_source_set_event_handler(assertType->globalTimer, ^{ 3352 enforceAssertionTypeTimeCap(assertType); 3353 }); 3354 3355 dispatch_source_set_cancel_handler(assertType->globalTimer, ^{ 3356 dispatch_release(assertType->globalTimer); 3357 assertType->globalTimer = NULL; 3358 }); 3359 3360 } 3361 else { 3362 dispatch_suspend(assertType->globalTimer); 3363 } 3364 3365 dispatch_source_set_timer(assertType->globalTimer, 3366 dispatch_time(DISPATCH_TIME_NOW, assertType->globalTimeout * NSEC_PER_SEC), 3367 DISPATCH_TIME_FOREVER, 0); 3368 dispatch_resume(assertType->globalTimer); 3369 3370} 3371 3372 3373static IOReturn raiseAssertion(assertion_t *assertion) 3374{ 3375 int idx = -1; 3376 int level; 3377 uint64_t currTime = getMonotonicTime(); 3378 uint32_t levelInt = 0; 3379 CFDateRef start_date = NULL; 3380 CFStringRef assertionTypeRef; 3381 CFNumberRef numRef = NULL; 3382 CFNumberRef levelNum = NULL; 3383 CFTimeInterval timeout = 0; 3384 assertionType_t *assertType; 3385 uint64_t assertion_id_64; 3386 3387 3388 assertionTypeRef = CFDictionaryGetValue(assertion->props, kIOPMAssertionTypeKey); 3389 3390 /* Find index for this assertion type */ 3391 idx = getAssertionTypeIndex(assertionTypeRef); 3392 if (idx < 0 ) 3393 return kIOReturnBadArgument; 3394 assertType = &gAssertionTypes[idx]; 3395 assertion->kassert = idx; 3396 3397 assertion_id_64 = MAKE_UNIQAID(currTime, idx, assertion->assertionId); 3398 CFNumberRef uniqueAID = CFNumberCreate(0, kCFNumberSInt64Type, &assertion_id_64); 3399 if (uniqueAID) { 3400 CFDictionarySetValue(assertion->props, kIOPMAssertionGlobalUniqueIDKey, uniqueAID); 3401 CFRelease(uniqueAID); 3402 } 3403 3404 /* Attach the Create Time */ 3405 start_date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); 3406 if (start_date) { 3407 CFDictionarySetValue(assertion->props, kIOPMAssertionCreateDateKey, start_date); 3408 CFRelease(start_date); 3409 } 3410 assertion->createTime = currTime; 3411 3412 3413 /* Is level set to 0 */ 3414 numRef = CFDictionaryGetValue(assertion->props, kIOPMAssertionLevelKey); 3415 if (isA_CFNumber(numRef)) { 3416 CFNumberGetValue(numRef, kCFNumberIntType, &level); 3417 if (level == kIOPMAssertionLevelOff) { 3418 /* Dump this assertion in inactive list */ 3419 insertInactiveAssertion(assertion, assertType); 3420 goto exit; 3421 } 3422 } 3423 else { 3424 /* If level is not set, set it to On */ 3425 levelInt = kIOPMAssertionLevelOn; 3426 levelNum = CFNumberCreate(0, kCFNumberIntType, &levelInt); 3427 CFDictionarySetValue(assertion->props, kIOPMAssertionLevelKey, levelNum); 3428 CFRelease(levelNum); 3429 } 3430 3431 /* Check if this is appplicable on battery power also */ 3432 if (assertType->flags & kAssertionTypeNotValidOnBatt) { 3433 CFBooleanRef val = NULL; 3434 val = CFDictionaryGetValue(assertion->props, kIOPMAssertionAppliesToLimitedPowerKey); 3435 if (isA_CFBoolean(val) && (val == kCFBooleanTrue)) { 3436 assertion->state |= kAssertionStateValidOnBatt; 3437 } 3438 } 3439 3440 numRef = CFDictionaryGetValue(assertion->props, kIOPMAssertionOnBehalfOfPID); 3441 if (isA_CFNumber(numRef)) { 3442 CFNumberGetValue(numRef, kCFNumberIntType, &assertion->causingPid); 3443 } 3444 3445 if (assertion->kassert == kDeclareUserActivityType) { 3446 CFBooleanRef val = NULL; 3447 val = CFDictionaryGetValue(assertion->props, kIOPMAssertionAppliesOnLidClose); 3448 if (isA_CFBoolean(val) && (val == kCFBooleanTrue)) { 3449 assertion->state |= kAssertionLidStateModifier; 3450 } 3451 } 3452 3453 /* Is this timed */ 3454 numRef = CFDictionaryGetValue(assertion->props, kIOPMAssertionTimeoutKey); 3455 if (isA_CFNumber(numRef)) 3456 CFNumberGetValue(numRef, kCFNumberDoubleType, &timeout); 3457 3458 if (assertType->flags & kAssertionTypeAutoTimed) { 3459 /* Restrict timeout to a max value of 'autoTimeout' */ 3460 if (!timeout || (timeout > assertType->autoTimeout)) 3461 timeout = assertType->autoTimeout; 3462 } 3463 if (timeout) { 3464 assertion->timeout = (uint64_t)timeout+currTime; // Absolute time at which assertion expires 3465 insertTimedAssertion(assertion, assertType, true); 3466 } 3467 else { 3468 /* Insert into active assertion list */ 3469 insertActiveAssertion(assertion, assertType); 3470 } 3471 3472 3473 if (assertType->handler) 3474 (*assertType->handler)(assertType, kAssertionOpRaise); 3475 3476 mt2RecordAssertionEvent(kAssertionOpRaise, assertion); 3477 3478exit: 3479 return kIOReturnSuccess; 3480 3481} 3482 3483 3484IOReturn doCreate( 3485 pid_t pid, 3486 CFMutableDictionaryRef newProperties, 3487 IOPMAssertionID *assertion_id, 3488 ProcessInfo **procInfo 3489 ) 3490{ 3491 int i; 3492 assertion_t *assertion = NULL; 3493 assertion_t *tmp_a = NULL; 3494 IOReturn result = kIOReturnSuccess; 3495 ProcessInfo *pinfo = NULL; 3496 assertionType_t *assertType = NULL; 3497 static uint32_t gNextAssertionIdx = 0; 3498 3499 // assertion_id will be set to kIOPMNullAssertionID on failure. 3500 *assertion_id = kIOPMNullAssertionID; 3501 3502 // Create a dispatch handler for process exit, if there isn't one 3503 if ( !(pinfo = processInfoRetain(pid)) ) { 3504 pinfo = processInfoCreate(pid); 3505 if (!pinfo) return kIOReturnNoMemory; 3506 3507 if (procInfo) *procInfo = pinfo; 3508 } 3509 3510 // Generate an id 3511 for (i=gNextAssertionIdx; CFDictionaryGetValueIfPresent(gAssertionsArray, 3512 (uintptr_t)i, (const void **)&tmp_a) == true; ) { 3513 i = (i+1) % kMaxAssertions; 3514 if (i == gNextAssertionIdx) break; 3515 } 3516 if (CFDictionaryGetValueIfPresent(gAssertionsArray, (uintptr_t)i, (const void **)&tmp_a) == true) { 3517 processInfoRelease(pid); 3518 return kIOReturnNoMemory; 3519 } 3520 3521 assertion = calloc(1, sizeof(assertion_t)); 3522 if (assertion == NULL) { 3523 processInfoRelease(pid); 3524 return kIOReturnNoMemory; 3525 } 3526 assertion->props = newProperties; 3527 CFRetain(newProperties); 3528 assertion->retainCnt = 1; 3529 assertion->pinfo = pinfo; 3530 3531 assertion->assertionId = ID_FROM_INDEX(i); 3532 CFDictionarySetValue(gAssertionsArray, (uintptr_t)i, (const void *)assertion); 3533 gNextAssertionIdx = (i+1) % kMaxAssertions; 3534 3535 result = raiseAssertion(assertion); 3536 if (result != kIOReturnSuccess) { 3537 processInfoRelease(pid); 3538 CFDictionaryRemoveValue(gAssertionsArray, (uintptr_t)i); 3539 CFRelease(assertion->props); 3540 free(assertion); 3541 3542 return result; 3543 } 3544 3545 assertType = &gAssertionTypes[assertion->kassert]; 3546 if (!(assertion->state & kAssertionStateInactive)) 3547 logAssertionEvent(kACreateLog, assertion); 3548 if (gAnyChange) notify_post( kIOPMAssertionsAnyChangedNotifyString ); 3549 3550 *assertion_id = assertion->assertionId; 3551 3552 return result; 3553} 3554 3555static void copyAssertion(assertion_t *assertion, CFMutableDictionaryRef assertionsDict) 3556{ 3557 bool created = false; 3558 CFNumberRef pidCF = NULL; 3559 CFMutableDictionaryRef processDict = NULL; 3560 CFMutableArrayRef pidAssertionsArr = NULL; 3561 CFStringRef processName = NULL; 3562 3563 pidCF = CFNumberCreate(0, kCFNumberIntType, &assertion->pinfo->pid); 3564 3565 processDict = (CFMutableDictionaryRef)CFDictionaryGetValue(assertionsDict, pidCF); 3566 if (processDict == NULL) 3567 { 3568 pidAssertionsArr = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); 3569 3570 processDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 2, 3571 &kCFTypeDictionaryKeyCallBacks, 3572 &kCFTypeDictionaryValueCallBacks); 3573 CFDictionarySetValue(processDict, 3574 CFSTR("PerTaskAssertions"), 3575 pidAssertionsArr); 3576 CFDictionarySetValue(processDict, 3577 kIOPMAssertionPIDKey, 3578 pidCF); 3579 3580 3581 CFDictionarySetValue(assertionsDict, pidCF, processDict); 3582 created = true; 3583 } 3584 else { 3585 pidAssertionsArr = (CFMutableArrayRef)CFDictionaryGetValue(processDict, CFSTR("PerTaskAssertions")); 3586 } 3587 3588 processName = assertion->pinfo->name; 3589 if (processName) { 3590 CFDictionarySetValue(assertion->props, kIOPMAssertionProcessNameKey, processName); 3591 } 3592 if (assertion->kassert < kIOPMNumAssertionTypes) { 3593 CFDictionarySetValue(assertion->props, kIOPMAssertionTrueTypeKey, assertion_types_arr[assertion->kassert]); 3594 } 3595 3596 CFArrayAppendValue(pidAssertionsArr, assertion->props); 3597 CFRelease(pidCF); 3598 3599 if (created) { 3600 CFRelease(pidAssertionsArr); 3601 CFRelease(processDict); 3602 } 3603} 3604 3605 3606static CFArrayRef copyPIDAssertionDictionaryFlattened(void) 3607{ 3608 CFMutableDictionaryRef assertionsDict = NULL; 3609 CFMutableArrayRef returnArray = NULL; 3610 CFDictionaryRef *assertionsDictArr; 3611 assertionType_t *assertType = NULL; 3612 CFIndex i, count; 3613 3614 3615 returnArray = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); 3616 3617 assertionsDict = CFDictionaryCreateMutable( 3618 kCFAllocatorDefault, 0, 3619 &kCFTypeDictionaryKeyCallBacks, 3620 &kCFTypeDictionaryValueCallBacks); 3621 3622 /* Go thru each assertion type and copy assertion props */ 3623 for (i=0; i < kIOPMNumAssertionTypes; i++) 3624 { 3625 if (i == kEnableIdleType) continue; 3626 assertType = &gAssertionTypes[i]; 3627 applyToAllAssertionsSync(assertType, false, ^(assertion_t *assertion) 3628 { 3629 copyAssertion(assertion, assertionsDict); 3630 }); 3631 3632 } 3633 3634 count = CFDictionaryGetCount(assertionsDict); 3635 assertionsDictArr = (CFDictionaryRef *)malloc(sizeof(CFDictionaryRef)*count); 3636 CFDictionaryGetKeysAndValues(assertionsDict, 3637 NULL, (const void **)assertionsDictArr); 3638 3639 for (i=0; i < count; i++) { 3640 CFArrayAppendValue(returnArray, assertionsDictArr[i]); 3641 } 3642 3643 free(assertionsDictArr); 3644 CFRelease(assertionsDict); 3645 3646 return returnArray; 3647} 3648 3649static IOReturn copyAssertionForID( 3650 pid_t inPID, int inID, 3651 CFMutableDictionaryRef *outAssertion) 3652{ 3653 IOReturn ret = kIOReturnBadArgument; 3654 assertion_t *assertion = NULL; 3655 3656 if (outAssertion) { 3657 *outAssertion = NULL; 3658 } 3659 else goto exit; 3660 3661 ret = lookupAssertion(inPID, inID, &assertion); 3662 if ((kIOReturnSuccess != ret)) { 3663 ret = kIOReturnNotFound; 3664 goto exit; 3665 } 3666 3667 CFRetain(assertion->props); 3668 *outAssertion = assertion->props; 3669 3670exit: 3671 return ret; 3672} 3673 3674static IOReturn doRetain(pid_t pid, IOPMAssertionID id) 3675{ 3676 IOReturn ret; 3677 assertion_t *assertion = NULL; 3678 3679 ret = lookupAssertion(pid, id, &assertion); 3680 3681 if ((kIOReturnSuccess != ret)) { 3682 return ret; 3683 } 3684 3685 assertion->retainCnt++; 3686 if (gAnyChange) notify_post( kIOPMAssertionsAnyChangedNotifyString ); 3687 3688 return kIOReturnSuccess; 3689} 3690 3691 3692 3693/* 3694 * Called when display Sleep Timer setting is changed. The timeout value 3695 * for all assertions of type kIOPMAssertionUserIsActive is modified 3696 * to reflect the new display Sleep timer value. 3697 */ 3698__private_extern__ void evalAllUserActivityAssertions(unsigned int dispSlpTimer) 3699{ 3700 3701 assertionType_t *assertType; 3702 int changeInSecs; 3703 assertion_t *assertion, *nextAssertion; 3704 uint64_t currTime = getMonotonicTime(); 3705 LIST_HEAD(, assertion) list = LIST_HEAD_INITIALIZER(list); // local list to hold assertions for which timeout is changed 3706 3707 if (gDisplaySleepTimer == (int)dispSlpTimer) 3708 return; 3709 3710 changeInSecs = ((int)dispSlpTimer - gDisplaySleepTimer) * 60; 3711 gDisplaySleepTimer = dispSlpTimer; 3712 3713 assertType = &gAssertionTypes[kDeclareUserActivityType]; 3714 3715 assertion = LIST_FIRST(&assertType->activeTimed); 3716 while( assertion ) 3717 { 3718 nextAssertion = LIST_NEXT(assertion, link); 3719 if (!(assertion->state & kAssertionTimeoutIsSystemTimer)) { 3720 assertion = nextAssertion; 3721 continue; 3722 } 3723 3724 if (gDisplaySleepTimer) { 3725 LIST_REMOVE(assertion, link); // Remove from timed list 3726 3727 if (assertion->timeout + changeInSecs < currTime) 3728 assertion->timeout = currTime; 3729 else 3730 assertion->timeout += changeInSecs; 3731 3732 LIST_INSERT_HEAD(&list, assertion, link); // add to local list 3733 } 3734 else { 3735 removeTimedAssertion(assertion, assertType, false); 3736 assertion->timeout = 0; 3737 insertActiveAssertion(assertion, assertType); 3738 } 3739 assertion = nextAssertion; 3740 } 3741 3742 // Walk thru local list and add them back to activeTimed list 3743 while( (assertion = LIST_FIRST(&list)) ) 3744 { 3745 LIST_REMOVE(assertion, link); 3746 insertByTimeout(assertion, assertType); 3747 } 3748 3749 assertion = LIST_FIRST(&assertType->active); 3750 while(assertion && gDisplaySleepTimer) 3751 { 3752 nextAssertion = LIST_NEXT(assertion, link); 3753 if (!(assertion->state & kAssertionTimeoutIsSystemTimer)) { 3754 assertion = nextAssertion; 3755 continue; 3756 } 3757 3758 assertion->timeout = currTime + (gDisplaySleepTimer * 60); 3759 3760 removeActiveAssertion(assertion, assertType); 3761 insertTimedAssertion(assertion, assertType, false); 3762 assertion = nextAssertion; 3763 } 3764 updateAssertionTimer(assertType); 3765 3766 if (assertType->handler) 3767 (*assertType->handler)(assertType, kAssertionOpRelease); 3768 3769 3770 if (gTimeoutChange) notify_post( kIOPMAssertionTimedOutNotifyString ); 3771 if (gAnyChange) notify_post( kIOPMAssertionsAnyChangedNotifyString ); 3772} 3773 3774 3775/* 3776 * Called when Idle Sleep Timer setting is changed. The timeout value 3777 * for assertions of type kIOPMAssertNetworkClientActive created by 3778 * API _io_pm_declare_network_client_active() are modified 3779 * to reflect the new idle Sleep timer value. 3780 */ 3781__private_extern__ void evalAllNetworkAccessAssertions() 3782{ 3783 3784 assertionType_t *assertType; 3785 int changeInSecs; 3786 assertion_t *assertion, *nextAssertion; 3787 uint64_t currTime = getMonotonicTime(); 3788 unsigned long idleSleepTimer = gIdleSleepTimer; 3789 LIST_HEAD(, assertion) list = LIST_HEAD_INITIALIZER(list); // local list to hold assertions for which timeout is changed 3790 3791 getIdleSleepTimer(&idleSleepTimer); 3792 changeInSecs = ((int)idleSleepTimer - gIdleSleepTimer) * 60; 3793 gIdleSleepTimer = idleSleepTimer; 3794 3795 if (changeInSecs == 0) return; 3796 3797 assertType = &gAssertionTypes[kNetworkAccessType]; 3798 3799 assertion = LIST_FIRST(&assertType->activeTimed); 3800 while( assertion ) 3801 { 3802 nextAssertion = LIST_NEXT(assertion, link); 3803 if (!(assertion->state & kAssertionTimeoutIsSystemTimer)) { 3804 assertion = nextAssertion; 3805 continue; 3806 } 3807 3808 if (gIdleSleepTimer) { 3809 LIST_REMOVE(assertion, link); // Remove from timed list 3810 3811 if (assertion->timeout + changeInSecs < currTime) 3812 assertion->timeout = currTime; 3813 else 3814 assertion->timeout += changeInSecs; 3815 3816 LIST_INSERT_HEAD(&list, assertion, link); // add to local list 3817 } 3818 else { 3819 removeTimedAssertion(assertion, assertType, false); 3820 assertion->timeout = 0; 3821 insertActiveAssertion(assertion, assertType); 3822 } 3823 assertion = nextAssertion; 3824 } 3825 3826 // Walk thru local list and add them back to activeTimed list 3827 while( (assertion = LIST_FIRST(&list)) ) 3828 { 3829 LIST_REMOVE(assertion, link); 3830 insertByTimeout(assertion, assertType); 3831 } 3832 3833 assertion = LIST_FIRST(&assertType->active); 3834 while( assertion && gIdleSleepTimer ) 3835 { 3836 nextAssertion = LIST_NEXT(assertion, link); 3837 if (!(assertion->state & kAssertionTimeoutIsSystemTimer)) { 3838 assertion = nextAssertion; 3839 continue; 3840 } 3841 3842 assertion->timeout = currTime + (gIdleSleepTimer * 60); 3843 3844 removeActiveAssertion(assertion, assertType); 3845 insertTimedAssertion(assertion, assertType, false); 3846 assertion = nextAssertion; 3847 } 3848 updateAssertionTimer(assertType); 3849 3850 if (assertType->handler) 3851 (*assertType->handler)(assertType, kAssertionOpRelease); 3852 3853 if (gTimeoutChange) notify_post( kIOPMAssertionTimedOutNotifyString ); 3854 if (gAnyChange) notify_post( kIOPMAssertionsAnyChangedNotifyString ); 3855} 3856 3857__private_extern__ void evalAllInteractivePushAssertions() 3858{ 3859 assertionType_t *assertType; 3860 uint64_t newTimeout; 3861 3862 assertType = &gAssertionTypes[kInteractivePushServiceType]; 3863 newTimeout = assertType->autoTimeout + getMonotonicTime(); 3864 3865 applyToAllAssertionsSync(assertType, false, ^(assertion_t *assertion) 3866 { 3867 CFNumberRef timeLeftCF = NULL; 3868 CFDateRef updateDate = NULL; 3869 3870 if (assertion->timeout > newTimeout) { 3871 assertion->timeout = newTimeout; 3872 3873 timeLeftCF = CFNumberCreate(0, kCFNumberIntType, &assertType->autoTimeout); 3874 if (timeLeftCF) { 3875 CFDictionarySetValue(assertion->props, kIOPMAssertionTimeoutTimeLeftKey, timeLeftCF); 3876 CFRelease(timeLeftCF); 3877 } 3878 3879 updateDate = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); 3880 if (updateDate) { 3881 CFDictionarySetValue(assertion->props, kIOPMAssertionTimeoutUpdateTimeKey, updateDate); 3882 CFRelease(updateDate); 3883 } 3884 } 3885 }); 3886 3887 updateAssertionTimer(assertType); 3888 3889 if (gTimeoutChange) notify_post( kIOPMAssertionTimedOutNotifyString ); 3890 if (gAnyChange) notify_post( kIOPMAssertionsAnyChangedNotifyString ); 3891} 3892 3893 3894 3895static void evaluateAssertions(void) 3896{ 3897 int i, pwrSrc; 3898 static int prevPwrSrc = -1; 3899 assertionType_t *assertType; 3900 3901 pwrSrc = _getPowerSource(); 3902 if (pwrSrc == prevPwrSrc) 3903 return; // If power source hasn't changed, there is nothing to do 3904 3905 prevPwrSrc = pwrSrc; 3906 3907 for (i=0; i < kIOPMNumAssertionTypes; i++) 3908 { 3909 assertType = &gAssertionTypes[i]; 3910 if (assertType->handler) { 3911 (*assertType->handler)(assertType, kAssertionOpEval); 3912 } 3913 } 3914 3915 // re-configure assertions that change with power source 3916 configAssertionType(kBackgroundTaskType, false); 3917 configAssertionType(kNetworkAccessType, false); 3918 configAssertionType(kInteractivePushServiceType, false); 3919 3920 /* Timeout for Interactive push assertions changes with power source change */ 3921 evalAllInteractivePushAssertions( ); 3922 cancelPowerNapStates( ); 3923 3924 for (i=0; i < kIOPMNumAssertionTypes; i++) 3925 { 3926 assertType = &gAssertionTypes[i]; 3927 if (assertType->flags & kAssertionTypeNotValidOnBatt) { 3928 applyToAllAssertionsSync(assertType, false, ^(assertion_t *assertion) 3929 { 3930 if ((pwrSrc == kBatteryPowered) && !(assertion->state & kAssertionStateValidOnBatt)) { 3931 updateAppStats(assertion, kAssertionOpRelease); 3932 } 3933 else if (pwrSrc != kBatteryPowered) { 3934 updateAppStats(assertion, kAssertionOpRaise); 3935 } 3936 }); 3937 } 3938 } 3939 logASLAssertionsAggregate(); 3940 3941} 3942 3943__private_extern__ void setSleepServicesTimeCap(uint32_t timeoutInMS) 3944{ 3945 assertionType_t *assertType; 3946 3947 assertType = &gAssertionTypes[kPushServiceTaskType]; 3948 3949 // Avoid duplicate resets to 0 3950 if ( (timeoutInMS == 0) && (assertType->globalTimeout == 0) ) 3951 return; 3952 3953 resetGlobalTimer(assertType, timeoutInMS/1000); 3954 if (timeoutInMS == 0) { 3955 CFRunLoopPerformBlock(_getPMRunLoop(), kCFRunLoopDefaultMode, 3956 ^{ enforceAssertionTypeTimeCap(assertType); }); 3957 CFRunLoopWakeUp(_getPMRunLoop()); 3958 } 3959} 3960 3961 3962static void configAssertionEffect(kerAssertionEffect idx) 3963{ 3964 gAssertionEffects[idx].effectIdx = idx; 3965 LIST_INIT(&gAssertionEffects[idx].assertTypes); 3966} 3967 3968 3969__private_extern__ void configAssertionType(kerAssertionType idx, bool initialConfig) 3970{ 3971 assertionHandler_f oldHandler = NULL; 3972 CFNumberRef idxRef = NULL; 3973 uint32_t oldFlags, flags; 3974 static bool prevBTdisable = false; 3975 kerAssertionType altIdx; 3976 assertionType_t *assertType; 3977 kerAssertionEffect prevEffect, newEffect; 3978 3979 // This can get called before gUserAssertionTypesDict is initialized 3980 if ( !gUserAssertionTypesDict ) 3981 return; 3982 3983 assertType = &gAssertionTypes[idx]; 3984 if (!initialConfig) { 3985 oldHandler = assertType->handler; 3986 oldFlags = assertType->flags; 3987 prevEffect = assertType->effectIdx; 3988 } 3989 3990 assertType->kassert = idx; 3991 switch(idx) 3992 { 3993 case kHighPerfType: 3994 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 3995 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeNeedsCPU, idxRef); 3996 assertType->handler = modifySettings; 3997 newEffect = kHighPerfEffect; 3998 break; 3999 4000 case kPreventIdleType: 4001 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4002 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypePreventUserIdleSystemSleep, idxRef); 4003 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeNoIdleSleep, idxRef); 4004 assertType->handler = modifySettings; 4005 4006 newEffect = kPrevIdleSlpEffect; 4007 assertType->flags |= kAssertionTypePreventAppSleep; 4008 break; 4009 4010 case kDisableInflowType: 4011 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4012 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeDisableInflow, idxRef); 4013 assertType->handler = handleBatteryAssertions; 4014 newEffect = kDisableInflowEffect; 4015 break; 4016 4017 4018 case kInhibitChargeType: 4019 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4020 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeInhibitCharging, idxRef); 4021 assertType->handler = handleBatteryAssertions; 4022 newEffect = kInhibitChargeEffect; 4023 break; 4024 4025 case kDisableWarningsType: 4026 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4027 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeDisableLowBatteryWarnings, idxRef); 4028 assertType->handler = handleBatteryAssertions; 4029 newEffect = kDisableWarningsEffect; 4030 break; 4031 4032 case kPreventDisplaySleepType: 4033 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4034 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypePreventUserIdleDisplaySleep, idxRef); 4035 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeNoDisplaySleep, idxRef); 4036 assertType->handler = setKernelAssertions; 4037 4038 assertType->flags |= kAssertionTypePreventAppSleep | kAssertionTypeLogOnCreate; 4039 newEffect = kPrevDisplaySlpEffect; 4040 break; 4041 4042 case kEnableIdleType: 4043 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4044 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeEnableIdleSleep, idxRef); 4045 assertType->handler = enableIdleHandler; 4046 newEffect = kEnableIdleEffect; 4047 break; 4048 4049 case kPreventSleepType: 4050 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4051 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypePreventSystemSleep, idxRef); 4052 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeDenySystemSleep, idxRef); 4053 assertType->flags |= kAssertionTypeNotValidOnBatt | kAssertionTypePreventAppSleep 4054 | kAssertionTypeLogOnCreate; 4055 assertType->handler = setKernelAssertions; 4056 4057 newEffect = kPrevDemandSlpEffect; 4058 break; 4059 4060 case kSRPreventSleepType: 4061 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4062 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertInternalPreventSleep, idxRef); 4063 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertMaintenanceActivity, idxRef); 4064 assertType->flags |= kAssertionTypeNotValidOnBatt | kAssertionTypePreventAppSleep | kAssertionTypeLogOnCreate; 4065 assertType->handler = setKernelAssertions; 4066 4067 newEffect = kPrevDemandSlpEffect; 4068 4069 break; 4070 4071 case kPreventDiskSleepType: 4072 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4073 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertPreventDiskIdle, idxRef); 4074 assertType->handler = modifySettings; 4075 newEffect = kPreventDiskSleepEffect; 4076 break; 4077 4078 case kExternalMediaType: 4079 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4080 CFDictionarySetValue(gUserAssertionTypesDict, _kIOPMAssertionTypeExternalMedia, idxRef); 4081 assertType->handler = setKernelAssertions; 4082 newEffect = kExternalMediaEffect; 4083 break; 4084 4085 case kDeclareUserActivityType: 4086 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4087 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionUserIsActive, idxRef); 4088 assertType->handler = setKernelAssertions; 4089 4090 assertType->flags |= kAssertionTypePreventAppSleep | kAssertionTypeLogOnCreate; 4091 newEffect = kPrevDisplaySlpEffect; 4092 break; 4093 4094 case kDeclareSystemActivityType: 4095 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4096 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeSystemIsActive, idxRef); 4097 assertType->handler = modifySettings; 4098 4099 newEffect = kPrevIdleSlpEffect; 4100 assertType->flags |= kAssertionTypePreventAppSleep | kAssertionTypeLogOnCreate; 4101 break; 4102 4103 case kPushServiceTaskType: 4104 if ( isA_SleepSrvcWake() && _SS_allowed() ) { 4105 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4106 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeApplePushServiceTask, idxRef); 4107 newEffect = kPrevDemandSlpEffect; 4108 } 4109 else { 4110 /* Set this as an alias to BackgroundTask assertion for non-sleep srvc wakes */ 4111 altIdx = kBackgroundTaskType; 4112 idxRef = CFNumberCreate(0, kCFNumberIntType, &altIdx); 4113 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeApplePushServiceTask, idxRef); 4114 newEffect = kNoEffect; 4115 } 4116 assertType->flags |= kAssertionTypeGloballyTimed | kAssertionTypePreventAppSleep; 4117 assertType->handler = setKernelAssertions; 4118 4119 4120 break; 4121 4122 case kBackgroundTaskType: 4123 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4124 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertionTypeBackgroundTask, idxRef); 4125 assertType->flags |= kAssertionTypeNotValidOnBatt | kAssertionTypePreventAppSleep; 4126 if (_DWBT_enabled()) { 4127 assertType->handler = setKernelAssertions; 4128 4129 if ( !isA_BTMtnceWake() ) { 4130 if (!prevBTdisable) { 4131 assertType->disableCnt++; 4132 prevBTdisable = true; 4133 } 4134 } 4135 else if (prevBTdisable) { 4136 if (assertType->disableCnt) 4137 assertType->disableCnt--; 4138 prevBTdisable = false; 4139 } 4140 newEffect = kPrevDemandSlpEffect; 4141 } 4142 else { 4143 assertType->handler = modifySettings; 4144 newEffect = kPrevIdleSlpEffect; 4145 if (prevBTdisable) { 4146 if (assertType->disableCnt) 4147 assertType->disableCnt--; 4148 prevBTdisable = false; 4149 } 4150 } 4151 4152 break; 4153 4154 case kTicklessDisplayWakeType: 4155#if TCPKEEPALIVE 4156 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4157 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertDisplayWake, idxRef); 4158 assertType->handler = displayWakeHandler; 4159 assertType->flags |= kAssertionTypePreventAppSleep | kAssertionTypeLogOnCreate; 4160 newEffect = kTicklessDisplayWakeEffect; 4161 assertType->entitlement = kIOPMDarkWakeControlEntitlement; 4162#else 4163 // TicklessDisplayWake is not a valid assertion type. 4164 // We are intentionally disabling it. 4165 altIdx = kPreventDisplaySleepType; 4166 idxRef = CFNumberCreate(0, kCFNumberIntType, &altIdx); 4167 newEffect = kNoEffect; 4168#endif 4169 break; 4170 4171 case kIntPreventDisplaySleepType: 4172 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4173 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertInternalPreventDisplaySleep, idxRef); 4174 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertRequiresDisplayAudio, idxRef); 4175 assertType->handler = setKernelAssertions; 4176 assertType->flags |= kAssertionTypeLogOnCreate; 4177 4178 newEffect = kPrevDisplaySlpEffect; 4179 break; 4180 4181 case kNetworkAccessType: 4182 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4183 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertNetworkClientActive, idxRef); 4184 assertType->flags |= kAssertionTypePreventAppSleep | kAssertionTypeLogOnCreate; 4185 4186 if (kACPowered == _getPowerSource()) { 4187 assertType->handler = setKernelAssertions; 4188 newEffect = kPrevDemandSlpEffect; 4189 } 4190 else { 4191 assertType->handler = modifySettings; 4192 newEffect = kPrevIdleSlpEffect; 4193 } 4194 break; 4195 4196 case kInteractivePushServiceType: 4197 newEffect = kNoEffect; 4198#if TCPKEEPALIVE 4199 if (getTCPKeepAliveState(NULL, 0) == kActive) { 4200 /* If keep alives are allowed */ 4201 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4202 4203 assertType->handler = setKernelAssertions; 4204 assertType->flags = kAssertionTypePreventAppSleep | kAssertionTypeAutoTimed; 4205 assertType->autoTimeout = getCurrentSleepServiceCapTimeout()/1000; 4206 4207 newEffect = kPrevDemandSlpEffect; 4208 } 4209 else if ( isA_SleepSrvcWake() && _SS_allowed() ) { 4210 /* else if in a sleep service window, set this as an alias to ApplePushServiceTask */ 4211 4212 altIdx = kPushServiceTaskType; 4213 idxRef = CFNumberCreate(0, kCFNumberIntType, &altIdx); 4214 4215 } 4216 else { 4217 /* else make this behave same as BackgroundTask assertion when PowerNap is disabled */ 4218 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4219 assertType->flags = kAssertionTypeNotValidOnBatt | kAssertionTypePreventAppSleep; 4220 assertType->flags |= kAssertionTypeAutoTimed; 4221 assertType->autoTimeout = getCurrentSleepServiceCapTimeout()/1000; 4222 assertType->handler = modifySettings; 4223 4224 newEffect = kPrevIdleSlpEffect; 4225 4226 } 4227#else 4228 if ( isA_SleepSrvcWake() && _SS_allowed() ) { 4229 altIdx = kPushServiceTaskType; 4230 } 4231 else { 4232 altIdx = kBackgroundTaskType; 4233 } 4234 4235 idxRef = CFNumberCreate(0, kCFNumberIntType, &altIdx); 4236#endif 4237 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertInteractivePushServiceTask, idxRef); 4238 assertType->entitlement = kIOPMInteractivePushEntitlement; 4239 4240 break; 4241 4242 case kReservePwrPreventIdleType: 4243#if TARGET_OS_EMBEDDED 4244 idxRef = CFNumberCreate(0, kCFNumberIntType, &idx); 4245#else 4246 altIdx = kPreventIdleType; 4247 idxRef = CFNumberCreate(0, kCFNumberIntType, &altIdx); 4248#endif 4249 CFDictionarySetValue(gUserAssertionTypesDict, kIOPMAssertAwakeReservePower, idxRef); 4250 assertType->flags |= kAssertionTypePreventAppSleep ; 4251 assertType->handler = modifySettings; 4252 newEffect = kPrevIdleSlpEffect; 4253 assertType->entitlement = kIOPMReservePwrCtrlEntitlement; 4254 4255 break; 4256 4257 4258 default: 4259 return; 4260 } 4261 if (idxRef) 4262 CFRelease(idxRef); 4263 4264 4265 if (assertType->disableCnt) { 4266 newEffect = kNoEffect; 4267 } 4268 4269 if (initialConfig) { 4270 assertType->effectIdx = newEffect; 4271 LIST_INSERT_HEAD(&gAssertionEffects[newEffect].assertTypes, assertType, link); 4272 } 4273 else if ((oldHandler != assertType->handler) || (prevEffect != newEffect)){ 4274 // Temporarily disable the assertion type and call the old handler. 4275 flags = assertType->flags; 4276 LIST_REMOVE(assertType, link); 4277 4278 oldHandler(assertType, kAssertionOpEval); 4279 assertType->flags = flags; 4280 if (gActivityAggCnt && (prevEffect != newEffect)) { 4281 applyToAllAssertionsSync(assertType, false, ^(assertion_t *assertion) 4282 { 4283 updateAppStats(assertion, kAssertionOpRelease); 4284 }); 4285 } 4286 4287 assertType->effectIdx = newEffect; 4288 4289 LIST_INSERT_HEAD(&gAssertionEffects[newEffect].assertTypes, assertType, link); 4290 4291 // Call the new handler 4292 if (newEffect != kNoEffect) 4293 assertType->handler(assertType, kAssertionOpEval); 4294 4295 if (gActivityAggCnt && (prevEffect != newEffect)) { 4296 applyToAllAssertionsSync(assertType, false, ^(assertion_t *assertion) 4297 { 4298 updateAppStats(assertion, kAssertionOpRaise); 4299 }); 4300 } 4301 4302 } 4303 else if (oldFlags != assertType->flags) { 4304 if (assertType->handler) 4305 assertType->handler(assertType, kAssertionOpEval); 4306 } 4307 4308} 4309 4310__private_extern__ void PMAssertions_prime(void) 4311{ 4312 4313 kerAssertionType idx = 0; 4314 kerAssertionEffect effctIdx = 0; 4315 int token; 4316 4317 gAssertionsArray = CFDictionaryCreateMutable(NULL, kMaxAssertions, NULL, NULL); 4318 gProcessDict = CFDictionaryCreateMutable(0, 0, NULL, NULL); 4319 4320 gUserAssertionTypesDict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 4321 4322 4323 assertion_types_arr[kHighPerfType] = kIOPMAssertionTypeNeedsCPU; 4324 assertion_types_arr[kPreventIdleType] = kIOPMAssertionTypePreventUserIdleSystemSleep; 4325 assertion_types_arr[kPreventSleepType] = kIOPMAssertionTypePreventSystemSleep; 4326 assertion_types_arr[kDisableInflowType] = kIOPMAssertionTypeDisableInflow; 4327 assertion_types_arr[kInhibitChargeType] = kIOPMAssertionTypeInhibitCharging; 4328 assertion_types_arr[kDisableWarningsType] = kIOPMAssertionTypeDisableLowBatteryWarnings; 4329 assertion_types_arr[kPreventDisplaySleepType] = kIOPMAssertionTypePreventUserIdleDisplaySleep; 4330 assertion_types_arr[kEnableIdleType] = kIOPMAssertionTypeEnableIdleSleep; 4331 assertion_types_arr[kExternalMediaType] = _kIOPMAssertionTypeExternalMedia; 4332 assertion_types_arr[kDeclareUserActivityType] = kIOPMAssertionUserIsActive; 4333 assertion_types_arr[kPushServiceTaskType] = kIOPMAssertionTypeApplePushServiceTask; 4334 assertion_types_arr[kBackgroundTaskType] = kIOPMAssertionTypeBackgroundTask; 4335 assertion_types_arr[kDeclareSystemActivityType] = kIOPMAssertionTypeSystemIsActive; 4336 assertion_types_arr[kSRPreventSleepType] = kIOPMAssertInternalPreventSleep; 4337 assertion_types_arr[kTicklessDisplayWakeType] = kIOPMAssertDisplayWake; 4338 assertion_types_arr[kPreventDiskSleepType] = kIOPMAssertPreventDiskIdle; 4339 assertion_types_arr[kNetworkAccessType] = kIOPMAssertNetworkClientActive; 4340 assertion_types_arr[kIntPreventDisplaySleepType] = kIOPMAssertInternalPreventDisplaySleep; 4341 assertion_types_arr[kInteractivePushServiceType] = kIOPMAssertInteractivePushServiceTask; 4342 assertion_types_arr[kReservePwrPreventIdleType] = kIOPMAssertAwakeReservePower; 4343 4344 for (effctIdx = 0; effctIdx < kMaxAssertionEffects; effctIdx++) 4345 configAssertionEffect(effctIdx); 4346 4347 for (idx = 0; idx < kIOPMNumAssertionTypes; idx++) 4348 configAssertionType(idx, true); 4349 4350 getDisplaySleepTimer(&gDisplaySleepTimer); 4351 getIdleSleepTimer(&gIdleSleepTimer); 4352 4353 // Reset kernel assertions to clear out old values from prior to powerd's crash 4354 sendUserAssertionsToKernel(0); 4355#if TARGET_OS_EMBEDDED 4356 /* 4357 * Disable Idle Sleep until some one comes and enables the idle sleep 4358 * by issuing 'kIOPMAssertionTypeEnableIdleSleep' assertion. 4359 */ 4360 gAssertionTypes[kEnableIdleType].handler( 4361 &gAssertionTypes[kEnableIdleType], kAssertionOpRelease); 4362 4363 /* BT assertions should have no effect on embedded */ 4364 disableAssertionType(kBackgroundTaskType); 4365#else 4366 4367 setAggregateLevel(kEnableIdleType, 1); /* Idle sleep is enabled by default */ 4368 gDebugFlags = kIOPMDebugAssertionASLLog; 4369 4370 notify_register_dispatch("com.apple.notificationcenter.pushdnd", &token, 4371 dispatch_get_main_queue(), 4372 ^(int t) { 4373 configAssertionType(kInteractivePushServiceType, false); }); 4374#endif 4375 notify_register_dispatch(kIOPMAssertionsCollectBTString, &token, 4376 dispatch_get_main_queue(), 4377 ^(int t) { /*Dummy registration to keep the key/value valid with notifyd */ }); 4378 4379 return; 4380} 4381 4382 4383 4384