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