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                                          &notifyInfo->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