1/*
2 * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <CoreFoundation/CoreFoundation.h>
25#include <CoreFoundation/CFPriv.h>
26#include <mach/mach.h>
27#include <IOKit/pwr_mgt/IOPMLib.h>
28#include <IOKit/pwr_mgt/IOPMLibPrivate.h>
29#include "IOSystemConfiguration.h"
30#include <sys/time.h>
31#include <notify.h>
32
33#include "powermanagement_mig.h"
34#include "powermanagement.h"
35
36#include <servers/bootstrap.h>
37
38
39#define kAssertionsArraySize        5
40
41#ifndef __CFRunLoopOptionsTakeAssertion
42#define __CFRunLoopOptionsTakeAssertion 8
43#endif
44
45#ifndef __CFRunLoopOptionsDropAssertion
46#define __CFRunLoopOptionsDropAssertion 9
47#endif
48
49static const int kMaxNameLength = 128;
50
51IOReturn _pm_connect(mach_port_t *newConnection);
52IOReturn _pm_disconnect(mach_port_t connection);
53
54
55__private_extern__ IOReturn _copyPMServerObject(int selector, int assertionID, CFTypeRef *objectOut);
56__private_extern__ io_registry_entry_t getPMRootDomainRef(void);
57
58
59/******************************************************************************
60 * IOPMAssertionCreate
61 *
62 * Deprecated but still supported wrapper for IOPMAssertionCreateWithProperties
63 ******************************************************************************/
64IOReturn IOPMAssertionCreate(
65                             CFStringRef             AssertionType,
66                             IOPMAssertionLevel      AssertionLevel,
67                             IOPMAssertionID         *AssertionID)
68{
69    return IOPMAssertionCreateWithName(AssertionType, AssertionLevel,
70                                       CFSTR("Nameless (via IOPMAssertionCreate)"), AssertionID);
71}
72
73/******************************************************************************
74 * IOPMAssertionCreateWithName
75 *
76 * Deprecated but still supported wrapper for IOPMAssertionCreateWithProperties
77 ******************************************************************************/
78IOReturn IOPMAssertionCreateWithName(
79                                     CFStringRef          AssertionType,
80                                     IOPMAssertionLevel   AssertionLevel __unused,
81                                     CFStringRef          AssertionName,
82                                     IOPMAssertionID      *AssertionID)
83{
84    CFMutableDictionaryRef      properties = NULL;
85    IOReturn                    result = kIOReturnError;
86
87    if (!AssertionName || !AssertionID || !AssertionType)
88        return kIOReturnBadArgument;
89
90    properties = CFDictionaryCreateMutable(0, 3, &kCFTypeDictionaryKeyCallBacks,
91                                           &kCFTypeDictionaryValueCallBacks);
92
93    if (properties)
94    {
95
96        CFDictionarySetValue(properties, kIOPMAssertionTypeKey, AssertionType);
97
98        CFDictionarySetValue(properties, kIOPMAssertionNameKey, AssertionName);
99
100        CFDictionarySetValue(properties, kIOPMAssertionUsedDeprecatedCreateAPIKey, kCFBooleanTrue);
101
102        result = IOPMAssertionCreateWithProperties(properties, AssertionID);
103
104        CFRelease(properties);
105    }
106
107    return result;
108}
109
110/******************************************************************************
111 * IOPMAssertionCreateWithDescription
112 *
113 ******************************************************************************/
114
115IOReturn    IOPMAssertionCreateWithDescription(
116    CFStringRef  AssertionType,
117    CFStringRef  Name,
118    CFStringRef  Details,
119    CFStringRef  HumanReadableReason,
120    CFStringRef  LocalizationBundlePath,
121    CFTimeInterval   Timeout,
122    CFStringRef  TimeoutAction,
123    IOPMAssertionID  *AssertionID)
124{
125    CFMutableDictionaryRef  descriptor = NULL;
126    IOReturn ret = kIOReturnError;
127
128    if (!AssertionType || !Name || !AssertionID) {
129        ret = kIOReturnBadArgument;
130        goto exit;
131    }
132
133    descriptor = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
134    if (!descriptor) {
135        goto exit;
136    }
137
138    CFDictionarySetValue(descriptor, kIOPMAssertionNameKey, Name);
139
140    CFDictionarySetValue(descriptor, kIOPMAssertionTypeKey, AssertionType);
141
142    if (Details) {
143        CFDictionarySetValue(descriptor, kIOPMAssertionDetailsKey, Details);
144    }
145    if (HumanReadableReason) {
146        CFDictionarySetValue(descriptor, kIOPMAssertionHumanReadableReasonKey, HumanReadableReason);
147    }
148    if (LocalizationBundlePath) {
149        CFDictionarySetValue(descriptor, kIOPMAssertionLocalizationBundlePathKey, LocalizationBundlePath);
150    }
151    if (Timeout) {
152        CFNumberRef Timeout_num = CFNumberCreate(0, kCFNumberDoubleType, &Timeout);
153        CFDictionarySetValue(descriptor, kIOPMAssertionTimeoutKey, Timeout_num);
154        CFRelease(Timeout_num);
155    }
156    if (TimeoutAction) {
157        CFDictionarySetValue(descriptor, kIOPMAssertionTimeoutActionKey, TimeoutAction);
158    }
159
160    ret = IOPMAssertionCreateWithProperties(descriptor, AssertionID);
161
162    CFRelease(descriptor);
163
164exit:
165    return ret;
166}
167
168/******************************************************************************
169 * IOPMAssertionCreateWithProperties
170 *
171 ******************************************************************************/
172IOReturn IOPMAssertionCreateWithProperties(
173    CFDictionaryRef         AssertionProperties,
174    IOPMAssertionID         *AssertionID)
175{
176    IOReturn                return_code     = kIOReturnError;
177    kern_return_t           kern_result     = KERN_SUCCESS;
178    mach_port_t             pm_server       = MACH_PORT_NULL;
179    IOReturn                err;
180    CFDataRef               flattenedProps  = NULL;
181    CFStringRef             assertionTypeString = NULL;
182    CFMutableDictionaryRef  mutableProps = NULL;
183    int                     disableAppSleep = 0;
184#if !TARGET_OS_IPHONE
185    static int              disableAppSleepToken = 0;
186    static int              enableAppSleepToken = 0;
187#else
188    static int              resyncToken = 0;
189    static CFMutableDictionaryRef  resyncCopy = NULL;
190#endif
191
192    if (!AssertionProperties || !AssertionID) {
193        return_code = kIOReturnBadArgument;
194        goto exit;
195    }
196
197    mutableProps = CFDictionaryCreateMutableCopy(NULL, 0, AssertionProperties);
198    if (!mutableProps) {
199        return_code = kIOReturnInternalError;
200        goto exit;
201    }
202
203    err = _pm_connect(&pm_server);
204    if(kIOReturnSuccess != err) {
205        return_code = kIOReturnInternalError;
206        goto exit;
207    }
208
209
210    assertionTypeString = CFDictionaryGetValue(AssertionProperties, kIOPMAssertionTypeKey);
211
212
213#if TARGET_OS_IPHONE
214
215    if (isA_CFString(assertionTypeString) &&
216                CFEqual(assertionTypeString, kIOPMAssertionTypeEnableIdleSleep) && !resyncToken) {
217
218        resyncCopy = CFDictionaryCreateMutableCopy(NULL, 0, AssertionProperties);
219        notify_register_dispatch( kIOUserAssertionReSync,
220                &resyncToken, dispatch_get_main_queue(),
221                ^(int t __unused) {
222                    IOPMAssertionID id;
223                    IOPMAssertionCreateWithProperties(resyncCopy, &id);
224                 });
225    }
226#endif
227    flattenedProps = CFPropertyListCreateData(0, mutableProps,
228                          kCFPropertyListBinaryFormat_v1_0, 0, NULL /* error */);
229    if (!flattenedProps) {
230        return_code = kIOReturnBadArgument;
231        goto exit;
232    }
233
234#if !TARGET_OS_IPHONE
235    if ( !disableAppSleepToken ) {
236       char notify_str[128];
237
238       snprintf(notify_str, sizeof(notify_str), "%s.%d",
239                            kIOPMDisableAppSleepPrefix, getpid());
240
241       notify_register_dispatch(
242             notify_str,
243             &disableAppSleepToken,
244             dispatch_get_main_queue(),
245             ^(int t __unused){
246                __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion, CFSTR("App is holding power assertion."));
247             });
248    }
249
250    if ( !enableAppSleepToken ) {
251       char notify_str[128];
252
253       snprintf(notify_str, sizeof(notify_str), "%s.%d",
254                            kIOPMEnableAppSleepPrefix, getpid());
255
256       notify_register_dispatch(
257             notify_str,
258             &enableAppSleepToken,
259             dispatch_get_main_queue(),
260             ^(int t __unused){
261                __CFRunLoopSetOptionsReason(__CFRunLoopOptionsDropAssertion, CFSTR("App released all power assertions."));
262             });
263    }
264#endif
265
266    kern_result = io_pm_assertion_create( pm_server,
267                                          (vm_offset_t)CFDataGetBytePtr(flattenedProps),
268                                          CFDataGetLength(flattenedProps),
269                                          (int *)AssertionID,
270                                          &disableAppSleep,
271                                          &return_code);
272
273    if(KERN_SUCCESS != kern_result) {
274        return_code = kIOReturnInternalError;
275    }
276#if !TARGET_OS_IPHONE
277    if (disableAppSleep) {
278        __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion,
279                    CFSTR("App is preventing system sleep with power assertion."));
280    }
281#endif
282
283exit:
284	if (flattenedProps) {
285		CFRelease(flattenedProps);
286	}
287
288    if (MACH_PORT_NULL != pm_server) {
289        _pm_disconnect(pm_server);
290    }
291
292    if (mutableProps)
293       CFRelease(mutableProps);
294    return return_code;
295}
296
297/******************************************************************************
298 * IOPMAssertionsRetain
299 *
300 ******************************************************************************/
301void IOPMAssertionRetain(IOPMAssertionID theAssertion)
302{
303    IOReturn                return_code     = kIOReturnError;
304    kern_return_t           kern_result     = KERN_SUCCESS;
305    mach_port_t             pm_server       = MACH_PORT_NULL;
306    IOReturn                err;
307    int                     disableAppSleep = 0;
308    int                     enableAppSleep = 0;
309
310    if (!theAssertion) {
311        return_code = kIOReturnBadArgument;
312        goto exit;
313    }
314
315    err = _pm_connect(&pm_server);
316    if(kIOReturnSuccess != err) {
317        return_code = kIOReturnInternalError;
318        goto exit;
319    }
320
321    kern_result = io_pm_assertion_retain_release( pm_server,
322                                         (int)theAssertion,
323                                         kIOPMAssertionMIGDoRetain,
324                                         &disableAppSleep,
325                                         &enableAppSleep,
326                                         &return_code);
327
328    if(KERN_SUCCESS != kern_result) {
329        return_code = kIOReturnInternalError;
330    }
331#if !TARGET_OS_IPHONE
332        if (disableAppSleep) {
333            __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion,
334                        CFSTR("App is preventing system sleep with power assertion."));
335        }
336#endif
337
338
339exit:
340    if (MACH_PORT_NULL != pm_server) {
341        _pm_disconnect(pm_server);
342    }
343    return;
344}
345
346
347/******************************************************************************
348 * IOPMAssertionsRelease
349 *
350 ******************************************************************************/
351IOReturn IOPMAssertionRelease(IOPMAssertionID AssertionID)
352{
353    IOReturn                return_code = kIOReturnError;
354    kern_return_t           kern_result = KERN_SUCCESS;
355    mach_port_t             pm_server = MACH_PORT_NULL;
356    IOReturn                err;
357    int                     disableAppSleep = 0;
358    int                     enableAppSleep = 0;
359
360    if (!AssertionID) {
361        return_code = kIOReturnBadArgument;
362        goto exit;
363    }
364
365    err = _pm_connect(&pm_server);
366    if(kIOReturnSuccess != err) {
367        return_code = kIOReturnInternalError;
368        goto exit;
369    }
370
371    kern_result = io_pm_assertion_retain_release( pm_server,
372                                                 (int)AssertionID,
373                                                 kIOPMAssertionMIGDoRelease,
374                                                 &disableAppSleep,
375                                                 &enableAppSleep,
376                                                 &return_code);
377
378    if(KERN_SUCCESS != kern_result) {
379        return_code = kIOReturnInternalError;
380    }
381#if !TARGET_OS_IPHONE
382        if (enableAppSleep) {
383            __CFRunLoopSetOptionsReason(__CFRunLoopOptionsDropAssertion,
384                    CFSTR("App is not preventing sleep any more."));
385        }
386#endif
387
388    _pm_disconnect(pm_server);
389exit:
390    return return_code;
391}
392
393
394/******************************************************************************
395 * IOPMAssertionSetProperty
396 *
397 ******************************************************************************/
398IOReturn IOPMAssertionSetProperty(IOPMAssertionID theAssertion, CFStringRef theProperty, CFTypeRef theValue)
399{
400    IOReturn                return_code     = kIOReturnError;
401    kern_return_t           kern_result     = KERN_SUCCESS;
402    mach_port_t             pm_server       = MACH_PORT_NULL;
403    CFDataRef               sendData        = NULL;
404    CFDictionaryRef         sendDict        = NULL;
405    int                     disableAppSleep = 0;
406    int                     enableAppSleep = 0;
407
408    if (!theAssertion) {
409        return_code = kIOReturnBadArgument;
410        goto exit;
411    }
412
413    return_code = _pm_connect(&pm_server);
414
415    if(kIOReturnSuccess != return_code) {
416        goto exit;
417    }
418
419    sendDict = CFDictionaryCreate(0, (const void **)&theProperty, (const void **)&theValue, 1,
420                          &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
421
422    if (sendDict) {
423        sendData = CFPropertyListCreateData(0, sendDict, kCFPropertyListBinaryFormat_v1_0, 0, NULL /* error */);
424        CFRelease(sendDict);
425    }
426
427
428    kern_result = io_pm_assertion_set_properties(pm_server,
429                                               (int)theAssertion,
430                                               (vm_offset_t)CFDataGetBytePtr(sendData),
431                                               CFDataGetLength(sendData),
432                                               &disableAppSleep,
433                                               &enableAppSleep,
434                                               (int *)&return_code);
435
436    if(KERN_SUCCESS != kern_result) {
437        return_code = kIOReturnInternalError;
438        goto exit;
439    }
440#if !TARGET_OS_IPHONE
441        if (disableAppSleep) {
442            __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion,
443                       CFSTR("App is preventing system sleep with power assertion."));
444        }
445        else if (enableAppSleep) {
446            __CFRunLoopSetOptionsReason(__CFRunLoopOptionsDropAssertion,
447                    CFSTR("App is not preventing sleep any more."));
448        }
449#endif
450
451
452exit:
453    if (sendData)
454        CFRelease(sendData);
455
456    if (MACH_PORT_NULL != pm_server) {
457        _pm_disconnect(pm_server);
458    }
459    return return_code;
460}
461
462/******************************************************************************
463 * IOPMAssertionSetTimeout
464 *
465 ******************************************************************************/
466IOReturn IOPMAssertionSetTimeout(IOPMAssertionID whichAssertion,
467                                 CFTimeInterval timeoutInterval)
468{
469    IOReturn            return_code = kIOReturnError;
470    CFNumberRef         intervalNum = NULL;
471    int                 timeoutSecs = (int)timeoutInterval;
472
473    intervalNum = CFNumberCreate(0, kCFNumberIntType, &timeoutSecs);
474
475    if (intervalNum)
476    {
477        return_code = IOPMAssertionSetProperty(whichAssertion, kIOPMAssertionTimeoutKey, intervalNum);
478
479        CFRelease(intervalNum);
480    }
481
482    return return_code;
483}
484
485/******************************************************************************
486 * IOPMAssertionDeclareNotificationEvent
487 *
488 ******************************************************************************/
489 IOReturn IOPMAssertionDeclareNotificationEvent(
490                        __unused CFStringRef          notificationName,
491                        __unused CFTimeInterval       secondsToDisplay,
492                        __unused IOPMAssertionID      *AssertionID)
493{
494#if TCPKEEPALIVE
495    IOPMAssertionID     id = kIOPMNullAssertionID;
496    IOReturn            ret = kIOReturnSuccess;
497    io_registry_entry_t rootdomain = getPMRootDomainRef();
498    CFBooleanRef        lidIsClosed = NULL;
499    CFBooleanRef        desktopMode = NULL;
500
501    if (rootdomain == MACH_PORT_NULL)
502        return kIOReturnInternalError;
503
504    desktopMode = IORegistryEntryCreateCFProperty(rootdomain,
505            CFSTR("DesktopMode"), kCFAllocatorDefault, 0);
506    lidIsClosed = IORegistryEntryCreateCFProperty(rootdomain,
507            CFSTR(kAppleClamshellStateKey), kCFAllocatorDefault, 0);
508
509    if ((kCFBooleanTrue == lidIsClosed) && (kCFBooleanFalse == desktopMode)) {
510        ret = kIOReturnNotReady;
511        goto exit;
512    }
513
514    ret = IOPMAssertionCreateWithDescription(
515            kIOPMAssertDisplayWake,
516            notificationName, NULL, NULL, NULL,
517            secondsToDisplay, kIOPMAssertionTimeoutActionRelease,
518            &id);
519    if (AssertionID)
520        *AssertionID = id;
521
522exit:
523    if (lidIsClosed) CFRelease(lidIsClosed);
524    if (desktopMode) CFRelease(desktopMode);
525
526    return ret;
527#endif
528    if (AssertionID) {
529        *AssertionID = kIOPMNullAssertionID;
530    }
531    return kIOReturnUnsupported;
532}
533
534/******************************************************************************
535 * IOPMAssertionDeclareSystemActivity
536 *
537 ******************************************************************************/
538IOReturn IOPMAssertionDeclareSystemActivity(
539                        CFStringRef             AssertionName,
540                        IOPMAssertionID         *AssertionID,
541                        IOPMSystemState         *SystemState)
542{
543    IOReturn        return_code = kIOReturnError;
544    mach_port_t     pm_server   = MACH_PORT_NULL;
545    kern_return_t   kern_result = KERN_SUCCESS;
546    IOReturn        err;
547
548    CFMutableDictionaryRef  properties      = NULL;
549    CFDataRef               flattenedProps  = NULL;
550
551    if (!AssertionName || !AssertionID || !SystemState) {
552        return_code = kIOReturnBadArgument;
553        goto exit;
554    }
555
556    err = _pm_connect(&pm_server);
557    if(kIOReturnSuccess != err) {
558        return_code = kIOReturnInternalError;
559        goto exit;
560    }
561
562    properties = CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks,
563                                           &kCFTypeDictionaryValueCallBacks);
564    CFDictionarySetValue(properties, kIOPMAssertionNameKey, AssertionName);
565
566    flattenedProps = CFPropertyListCreateData(0, properties,
567                          kCFPropertyListBinaryFormat_v1_0, 0, NULL /* error */);
568    if (!flattenedProps) {
569        return_code = kIOReturnBadArgument;
570        goto exit;
571    }
572
573    kern_result = io_pm_declare_system_active(
574                        pm_server,
575                        (int *)SystemState,
576                        (vm_offset_t)CFDataGetBytePtr(flattenedProps),
577                        CFDataGetLength(flattenedProps),
578                        (int *)AssertionID,
579                        &return_code);
580
581    if(KERN_SUCCESS != kern_result) {
582        return_code = kIOReturnInternalError;
583        goto exit;
584    }
585exit:
586    if (flattenedProps)
587        CFRelease(flattenedProps);
588
589    if (properties)
590        CFRelease(properties);
591
592    if (MACH_PORT_NULL != pm_server) {
593        _pm_disconnect(pm_server);
594    }
595
596    return return_code;
597
598}
599/******************************************************************************
600 * IOPMAssertionDeclareUserActivity
601 *
602 ******************************************************************************/
603IOReturn IOPMAssertionDeclareUserActivity(
604                        CFStringRef          AssertionName,
605                        IOPMUserActiveType   userType,
606                        IOPMAssertionID      *AssertionID)
607{
608
609    IOReturn        return_code = kIOReturnError;
610    mach_port_t     pm_server = MACH_PORT_NULL;
611    kern_return_t   kern_result = KERN_SUCCESS;
612    IOReturn        err;
613    static struct timeval prev_ts = {0,0};
614    struct timeval ts;
615    int                     disableAppSleep = 0;
616
617
618    CFMutableDictionaryRef  properties = NULL;
619    CFDataRef               flattenedProps  = NULL;
620
621    if (!AssertionName || !AssertionID) {
622        return_code = kIOReturnBadArgument;
623        goto exit;
624    }
625
626    gettimeofday(&ts, NULL);
627    if (ts.tv_sec - prev_ts.tv_sec <= 5) {
628       if ( *AssertionID == kIOPMNullAssertionID )
629          *AssertionID = 0xabcd; /* Give a dummy id */
630       return_code = kIOReturnSuccess;
631       goto exit;
632    }
633    prev_ts = ts;
634
635    err = _pm_connect(&pm_server);
636    if(kIOReturnSuccess != err) {
637        return_code = kIOReturnInternalError;
638        goto exit;
639    }
640
641    properties = CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks,
642                                           &kCFTypeDictionaryValueCallBacks);
643    CFDictionarySetValue(properties, kIOPMAssertionNameKey, AssertionName);
644
645    flattenedProps = CFPropertyListCreateData(0, properties,
646                          kCFPropertyListBinaryFormat_v1_0, 0, NULL /* error */);
647    if (!flattenedProps) {
648        return_code = kIOReturnBadArgument;
649        goto exit;
650    }
651
652
653    kern_result = io_pm_declare_user_active(
654                        pm_server,
655                        userType,
656                        (vm_offset_t)CFDataGetBytePtr(flattenedProps),
657                        CFDataGetLength(flattenedProps),
658                        (int *)AssertionID,
659                        &disableAppSleep,
660                        &return_code);
661
662
663    if(KERN_SUCCESS != kern_result) {
664        return_code = kIOReturnInternalError;
665        goto exit;
666    }
667#if !TARGET_OS_IPHONE
668        if (disableAppSleep) {
669            __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion,
670                        CFSTR("App is preventing system sleep with power assertion."));
671        }
672#endif
673
674
675exit:
676    if (flattenedProps)
677        CFRelease(flattenedProps);
678
679    if (properties)
680        CFRelease(properties);
681
682    if (MACH_PORT_NULL != pm_server) {
683        _pm_disconnect(pm_server);
684    }
685
686    return return_code;
687}
688
689
690/******************************************************************************
691 * IOPMDeclareNetworkClientActivity
692 *
693 ******************************************************************************/
694IOReturn IOPMDeclareNetworkClientActivity(
695                        CFStringRef          AssertionName,
696                        IOPMAssertionID      *AssertionID)
697{
698
699    IOReturn        return_code = kIOReturnError;
700    mach_port_t     pm_server = MACH_PORT_NULL;
701    kern_return_t   kern_result = KERN_SUCCESS;
702    IOReturn        err;
703    int             disableAppSleep = 0;
704
705
706    CFMutableDictionaryRef  properties = NULL;
707    CFDataRef               flattenedProps  = NULL;
708
709    if (!AssertionName || !AssertionID) {
710        return_code = kIOReturnBadArgument;
711        goto exit;
712    }
713
714    err = _pm_connect(&pm_server);
715    if(kIOReturnSuccess != err) {
716        return_code = kIOReturnInternalError;
717        goto exit;
718    }
719
720    properties = CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks,
721                                           &kCFTypeDictionaryValueCallBacks);
722    CFDictionarySetValue(properties, kIOPMAssertionNameKey, AssertionName);
723
724    flattenedProps = CFPropertyListCreateData(0, properties,
725                          kCFPropertyListBinaryFormat_v1_0, 0, NULL /* error */);
726    if (!flattenedProps) {
727        return_code = kIOReturnBadArgument;
728        goto exit;
729    }
730
731
732    kern_result = io_pm_declare_network_client_active(
733                        pm_server,
734                        (vm_offset_t)CFDataGetBytePtr(flattenedProps),
735                        CFDataGetLength(flattenedProps),
736                        (int *)AssertionID,
737                        &disableAppSleep,
738                        &return_code);
739
740
741    if(KERN_SUCCESS != kern_result) {
742        return_code = kIOReturnInternalError;
743        goto exit;
744    }
745#if !TARGET_OS_IPHONE
746        if (disableAppSleep) {
747            __CFRunLoopSetOptionsReason(__CFRunLoopOptionsTakeAssertion,
748                        CFSTR("App is preventing system sleep with power assertion."));
749        }
750#endif
751
752
753exit:
754    if (flattenedProps)
755        CFRelease(flattenedProps);
756
757    if (properties)
758        CFRelease(properties);
759
760    if (MACH_PORT_NULL != pm_server) {
761        _pm_disconnect(pm_server);
762    }
763
764    return return_code;
765}
766
767
768
769/******************************************************************************
770 * IOPMCopyAssertionsByProcess
771 *
772 ******************************************************************************/
773IOReturn IOPMCopyAssertionsByProcess(CFDictionaryRef         *AssertionsByPid)
774{
775    IOReturn                return_code     = kIOReturnError;
776    CFArrayRef              flattenedDictionary = NULL;
777    int                     flattenedArrayCount = 0;
778    CFNumberRef             *newDictKeys = NULL;
779    CFArrayRef              *newDictValues = NULL;
780
781    if (!AssertionsByPid)
782        return kIOReturnBadArgument;
783
784    return_code = _copyPMServerObject(kIOPMAssertionMIGCopyAll, 0, (CFTypeRef *)&flattenedDictionary);
785
786    if (kIOReturnSuccess != return_code)
787        goto exit;
788
789    /*
790     * This API returns a dictionary whose keys are process ID's.
791     * This is perfectly acceptable in CoreFoundation, EXCEPT that you cannot
792     * serialize a dictionary with CFNumbers for keys using CF or IOKit
793     * serialization.
794     *
795     * To serialize this dictionary and pass it from configd to the caller's process,
796     * we re-formatted it as a "flattened" array of dictionaries in configd,
797     * and we will re-constitute with pid's for keys here.
798     *
799     * Next time around, I will simply not use CFNumberRefs for keys in API.
800     */
801
802
803    if (flattenedDictionary) {
804        flattenedArrayCount = CFArrayGetCount(flattenedDictionary);
805    }
806
807    if (0 == flattenedArrayCount) {
808        goto exit;
809    }
810
811    newDictKeys = (CFNumberRef *)malloc(sizeof(CFTypeRef) * flattenedArrayCount);
812    newDictValues = (CFArrayRef *)malloc(sizeof(CFTypeRef) * flattenedArrayCount);
813
814    if (!newDictKeys || !newDictValues)
815        goto exit;
816
817    for (int i=0; i < flattenedArrayCount; i++)
818    {
819        CFDictionaryRef dictionaryAtIndex = NULL;
820
821        if ((dictionaryAtIndex = CFArrayGetValueAtIndex(flattenedDictionary, i)))
822        {
823
824            newDictKeys[i]      = CFDictionaryGetValue(dictionaryAtIndex, kIOPMAssertionPIDKey);
825            newDictValues[i]    = CFDictionaryGetValue(dictionaryAtIndex, CFSTR("PerTaskAssertions"));
826        }
827    }
828
829    *AssertionsByPid = CFDictionaryCreate(kCFAllocatorDefault,
830                                          (const void **)newDictKeys, (const void **)newDictValues, flattenedArrayCount,
831                                          &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
832
833    return_code = kIOReturnSuccess;
834
835exit:
836    if (newDictKeys)
837        free(newDictKeys);
838    if (newDictValues)
839        free(newDictValues);
840    if (flattenedDictionary)
841        CFRelease(flattenedDictionary);
842    return return_code;
843}
844
845/******************************************************************************
846 * IOPMAssertionCopyProperties
847 *
848 ******************************************************************************/
849CFDictionaryRef IOPMAssertionCopyProperties(IOPMAssertionID theAssertion)
850{
851    CFDictionaryRef         theResult       = NULL;
852
853    _copyPMServerObject(kIOPMAssertionMIGCopyOneAssertionProperties, theAssertion, (CFTypeRef *)&theResult);
854
855    return theResult;
856}
857
858/******************************************************************************
859 * IOPMCopyTimedOutAssertions
860 *
861 ******************************************************************************/
862IOReturn IOPMCopyTimedOutAssertions(CFArrayRef *timedOutAssertions)
863{
864    if (!timedOutAssertions)
865        return kIOReturnBadArgument;
866
867    return _copyPMServerObject(kIOPMAssertionMIGCopyTimedOutAssertions, 0, (CFTypeRef *)timedOutAssertions);
868}
869
870/******************************************************************************
871 * IOPMCopyAssertionsStatus
872 *
873 ******************************************************************************/
874IOReturn IOPMCopyAssertionsStatus(CFDictionaryRef *AssertionsStatus)
875{
876    if (!AssertionsStatus)
877        return kIOReturnBadArgument;
878
879    return _copyPMServerObject(kIOPMAssertionMIGCopyStatus, 0, (CFTypeRef *)AssertionsStatus);
880}
881
882/******************************************************************************
883 * _copyPMServerObject
884 *
885 ******************************************************************************/
886__private_extern__ IOReturn _copyPMServerObject(int selector, int assertionID, CFTypeRef *objectOut)
887{
888    IOReturn                return_code     = kIOReturnError;
889    kern_return_t           kern_result     = KERN_SUCCESS;
890    mach_port_t             pm_server       = MACH_PORT_NULL;
891    vm_offset_t             theResultsPtr   = 0;
892    mach_msg_type_number_t  theResultsCnt   = 0;
893    CFDataRef               theResultData   = NULL;
894
895    *objectOut = NULL;
896
897    if(kIOReturnSuccess != (return_code = _pm_connect(&pm_server))) {
898        return kIOReturnNotFound;
899    }
900
901    kern_result = io_pm_assertion_copy_details(pm_server, assertionID, selector,
902                                             &theResultsPtr, &theResultsCnt, &return_code);
903
904    if(KERN_SUCCESS != kern_result) {
905        return kIOReturnInternalError;
906    }
907
908    if (return_code != kIOReturnSuccess)
909        return return_code;
910
911    if ((theResultData = CFDataCreate(0, (const UInt8 *)theResultsPtr, (CFIndex)theResultsCnt)))
912    {
913        *objectOut = CFPropertyListCreateWithData(0, theResultData, kCFPropertyListImmutable, NULL, NULL);
914        CFRelease(theResultData);
915    }
916
917    if (theResultsPtr && 0 != theResultsCnt) {
918        vm_deallocate(mach_task_self(), theResultsPtr, theResultsCnt);
919    }
920
921    if (MACH_PORT_NULL != pm_server) {
922        _pm_disconnect(pm_server);
923    }
924
925    return kIOReturnSuccess;
926}
927
928