1/*
2 * Copyright (c) 2007 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
26#include <syslog.h>
27#include <unistd.h>
28#include <grp.h>
29#include <pwd.h>
30#include <mach/mach.h>
31#include <servers/bootstrap.h>
32#include <notify.h>
33#include <asl.h>
34#include <uuid/uuid.h>
35#include <pthread.h>
36#include <bsm/libbsm.h>
37#include <sys/sysctl.h>
38#include <xpc/private.h>
39#if !TARGET_OS_EMBEDDED
40#include <IOKit/platform/IOPlatformSupportPrivate.h>
41#include <AssertMacros.h>
42#endif
43#include <IOKit/pwr_mgt/IOPMLibPrivate.h>
44#include <IOKit/hid/IOHIDKeys.h>
45
46#include <Security/SecTask.h>
47
48#include "powermanagementServer.h" // mig generated
49
50#include "PMStore.h"
51#include "PMSettings.h"
52#include "UPSLowPower.h"
53#include "BatteryTimeRemaining.h"
54#include "AutoWakeScheduler.h"
55#include "RepeatingAutoWake.h"
56#include "PMAssertions.h"
57#include "PrivateLib.h"
58#include "TTYKeepAwake.h"
59#include "PMSystemEvents.h"
60#include "SystemLoad.h"
61#include "PMConnection.h"
62#include "ExternalMedia.h"
63#include "Platform.h"
64
65// To support importance donation across IPCs
66#include <libproc_internal.h>
67
68#define kIOPMAppName        "Power Management configd plugin"
69#define kIOPMPrefsPath      "com.apple.PowerManagement.xml"
70#define pwrLogDirName       "/System/Library/PowerEvents"
71
72#ifndef kIOUPSDeviceKey
73// Also defined in ioupsd/IOUPSPrivate.h
74#define kIOUPSDeviceKey             "UPSDevice"
75#define kIOPowerDeviceUsageKey      0x84
76#define kIOBatterySystemUsageKey    0x85
77#endif
78
79/*
80 * BSD notifications from loginwindow indicating shutdown
81 */
82// kLWShutdownInitiated
83//   User clicked shutdown: may be aborted later
84#define kLWShutdowntInitiated    "com.apple.system.loginwindow.shutdownInitiated"
85
86// kLWRestartInitiated
87//   User clicked restart: may be aborted later
88#define kLWRestartInitiated     "com.apple.system.loginwindow.restartinitiated"
89
90// kLWLogoutCancelled
91//   A previously initiated shutdown, restart, or logout, has been cancelled.
92#define kLWLogoutCancelled      "com.apple.system.loginwindow.logoutcancelled"
93
94// kLWLogoutPointOfNoReturn
95//   A previously initiated shutdown, restart, or logout has succeeded, and is
96//   no longer abortable by anyone. Point of no return!
97#define kLWLogoutPointOfNoReturn    "com.apple.system.loginwindow.logoutNoReturn"
98
99// kLWSULogoutInitiated
100//   Loginwindow is beginning a sequence of 1. logout, 2. software update, 3. then restart.
101#define kLWSULogoutInitiated     "com.apple.system.loginwindow.sulogoutinitiated"
102
103#define kDWTMsgHandlerDelay         10  // Time(in secs) for which DW Thermal msg handler is delayed
104
105#define LogObjectRetainCount(x, y) do {} while(0)
106/* #define LogObjectRetainCount(x, y) do { \
107    asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s: kernel retain = %d, user retain = %d\n", \
108        x, IOObjectGetKernelRetainCount(y), IOObjectGetUserRetainCount(y)); } while(0)
109*/
110
111// Global keys
112static CFStringRef              gTZNotificationNameString           = NULL;
113
114static SCPreferencesRef         gESPreferences                      = NULL;
115
116static io_connect_t             _pm_ack_port                        = 0;
117static io_iterator_t            _ups_added_noteref                  = 0;
118static int                      _alreadyRunningIOUPSD               = 0;
119
120static int                      gCPUPowerNotificationToken          = 0;
121static bool                     gExpectingWakeFromSleepClockResync  = false;
122static CFAbsoluteTime           *gLastWakeTime                      = NULL;
123static CFTimeInterval           *gLastSMCS3S0WakeInterval           = NULL;
124static CFStringRef              gCachedNextSleepWakeUUIDString      = NULL;
125#if !TARGET_OS_EMBEDDED
126static int                      gLastWakeTimeToken                  = -1;
127static int                      gLastSMCS3S0WakeIntervalToken       = -1;
128#endif
129
130typedef struct {
131    int  shutdown;
132    int  restart;
133    int  cancel;
134    int  pointofnoreturn;
135    int  su;
136} LoginWindowNotifyTokens;
137static LoginWindowNotifyTokens  lwNotify = {0,0,0,0,0};
138
139static CFStringRef              gConsoleNotifyKey                   = NULL;
140static bool                     gDisplayIsAsleep = false;
141static CFAbsoluteTime           gSleepFromUserWakeTime = 0;
142static struct timeval           gLastSleepTime                      = {0, 0};
143
144static mach_port_t              serverPort                          = MACH_PORT_NULL;
145__private_extern__ CFMachPortRef pmServerMachPort                   = NULL;
146#if !TARGET_OS_EMBEDDED
147static bool                     gSMCSupportsWakeupTimer             = true;
148static int                      _darkWakeThermalEventCount          = 0;
149static dispatch_source_t        gDWTMsgDispatch; /* Darkwake thermal emergency message handler dispatch */
150#endif
151
152#if TCPKEEPALIVE
153extern TCPKeepAliveStruct           *gTCPKeepAlive;
154#endif
155
156// defined by MiG
157extern boolean_t powermanagement_server(mach_msg_header_t *, mach_msg_header_t *);
158
159
160// foward declarations
161static void initializeESPrefsDynamicStore(void);
162static void initializeInterestNotifications(void);
163static void initializeHIDInterestNotifications(
164                int usagePage,
165                IONotificationPortRef notify_port);
166static void initializeTimezoneChangeNotifications(void);
167static void initializeCalendarResyncNotification(void);
168static void initializeShutdownNotifications(void);
169static void initializeRootDomainInterestNotifications(void);
170#if !TARGET_OS_EMBEDDED
171static void initializeUserNotifications(void);
172static void enableSleepWakeWdog();
173#endif
174static void initializeSleepWakeNotifications(void);
175
176static void SleepWakeCallback(void *,io_service_t, natural_t, void *);
177static void ESPrefsHaveChanged(
178                SCPreferencesRef prefs,
179                SCPreferencesNotification notificationType,
180                void *info);
181static void _ioupsd_exited(pid_t, int, struct rusage *, void *);
182static void UPSDeviceAdded(void *, io_iterator_t);
183static void ioregBatteryMatch(void *, io_iterator_t);
184static void ioregBatteryInterest(void *, io_service_t, natural_t, void *);
185static void RootDomainInterest(void *, io_service_t, natural_t, void *);
186static void broadcastGMTOffset(void);
187
188static void pushNewSleepWakeUUID(void);
189
190static void calendarRTCDidResync(
191                CFMachPortRef port,
192                void *msg,
193                CFIndex size,
194                void *info);
195
196static void lwShutdownCallback(
197                CFMachPortRef port,
198                void *msg,
199                CFIndex size,
200                void *info);
201
202static void timeZoneChangedCallBack(
203                CFNotificationCenterRef center,
204                void *observer,
205                CFStringRef notificationName,
206                const void *object,
207                CFDictionaryRef userInfo);
208
209static void displayMatched(void *, io_iterator_t);
210static void displayPowerStateChange(
211                void *ref,
212                io_service_t service,
213                natural_t messageType,
214                void *arg);
215
216static boolean_t pm_mig_demux(
217                mach_msg_header_t * request,
218                mach_msg_header_t * reply);
219
220static void mig_server_callback(
221                CFMachPortRef port,
222                void *msg,
223                CFIndex size,
224                void *info);
225
226static void incoming_XPC_connection(xpc_connection_t);
227static void xpc_register(void);
228
229static void AppClaimWakeReason(xpc_object_t claim);
230
231
232
233
234kern_return_t _io_pm_set_active_profile(
235                mach_port_t         server,
236                audit_token_t       token,
237                vm_offset_t         profiles_ptr,
238                mach_msg_type_number_t    profiles_len,
239                int                 *result);
240
241kern_return_t _io_pm_last_wake_time(
242                mach_port_t             server,
243                vm_offset_t             *out_wake_data,
244                mach_msg_type_number_t  *out_wake_len,
245                vm_offset_t             *out_delta_data,
246                mach_msg_type_number_t  *out_delta_len,
247                int                     *return_val);
248
249
250
251static CFStringRef
252serverMPCopyDescription(const void *info)
253{
254    return CFStringCreateWithFormat(NULL, NULL, CFSTR("<IOKit Power Management MIG server>"));
255}
256
257// Callback is registered in PrivateLib.c
258__private_extern__ void dynamicStoreNotifyCallBack(
259                SCDynamicStoreRef   store,
260                CFArrayRef          changedKeys,
261                void                *info);
262
263
264/* load
265 *
266 * configd entry point
267 */
268
269
270
271
272int main(int argc __unused, char *argv[] __unused)
273{
274    CFRunLoopSourceRef      cfmp_rls = 0;
275    CFMachPortContext       context  = { 0, (void *)1, NULL, NULL, serverMPCopyDescription };
276    kern_return_t           kern_result = 0;
277
278    xpc_register();
279
280    kern_result = bootstrap_check_in(
281                            bootstrap_port,
282                            kIOPMServerBootstrapName,
283                            &serverPort);
284
285#if TARGET_OS_EMBEDDED
286    if (BOOTSTRAP_SUCCESS != kern_result) {
287        kern_result = mach_port_allocate(
288                                mach_task_self(),
289                                MACH_PORT_RIGHT_RECEIVE,
290                                &serverPort);
291
292        if (KERN_SUCCESS == kern_result) {
293            kern_result = mach_port_insert_right(
294                                mach_task_self(),
295                                serverPort, serverPort,
296                                MACH_MSG_TYPE_MAKE_SEND);
297        }
298
299        if (KERN_SUCCESS == kern_result) {
300            kern_result = bootstrap_register(
301                                bootstrap_port,
302                                kIOPMServerBootstrapName,
303                                serverPort);
304        }
305    }
306#endif
307
308    if (BOOTSTRAP_SUCCESS != kern_result) {
309        syslog(LOG_ERR, "PM configd: bootstrap_register \"%s\" error = %d\n",
310                                kIOPMServerBootstrapName, kern_result);
311    }
312
313    if (MACH_PORT_NULL != serverPort)
314    {
315        // Finish setting up mig handler callback on pmServerMachPort
316        pmServerMachPort = _SC_CFMachPortCreateWithPort(
317                                "PowerManagement",
318                                serverPort,
319                                mig_server_callback,
320                                &context);
321    }
322    if (pmServerMachPort) {
323        cfmp_rls = CFMachPortCreateRunLoopSource(0, pmServerMachPort, 0);
324        if (cfmp_rls) {
325            CFRunLoopAddSource(CFRunLoopGetCurrent(), cfmp_rls, kCFRunLoopDefaultMode);
326            CFRelease(cfmp_rls);
327        }
328    }
329
330    _getPMRunLoop();
331
332    PMStoreLoad();
333
334    initializeESPrefsDynamicStore();
335    initializeInterestNotifications();
336    initializeTimezoneChangeNotifications();
337    initializeCalendarResyncNotification();
338    initializeShutdownNotifications();
339    initializeRootDomainInterestNotifications();
340
341#if !TARGET_OS_EMBEDDED
342    initializeUserNotifications();
343    _oneOffHacksSetup();
344#endif
345
346    initializeSleepWakeNotifications();
347
348    // Prime the messagetracer UUID pump
349    pushNewSleepWakeUUID();
350
351    BatteryTimeRemaining_prime();
352    PMSettings_prime();
353    AutoWake_prime();
354    PMAssertions_prime();
355    PMSystemEvents_prime();
356    SystemLoad_prime();
357    PMConnection_prime();
358
359#if !TARGET_OS_EMBEDDED
360    UPSLowPower_prime();
361    TTYKeepAwake_prime();
362    ExternalMedia_prime();
363
364    createOnBootAssertions();
365    enableSleepWakeWdog();
366#endif
367
368    _unclamp_silent_running(false);
369    notify_post(kIOUserAssertionReSync);
370    logASLMessagePMStart();
371
372    CFRunLoopRun();
373    return 0;
374}
375
376
377
378
379static void ioregBatteryMatch(
380    void *refcon,
381    io_iterator_t b_iter)
382{
383    IOPMBattery                 *tracking;
384    IONotificationPortRef       notify = (IONotificationPortRef)refcon;
385    io_registry_entry_t         battery;
386    io_object_t                 notification_ref;
387
388    while((battery = (io_registry_entry_t)IOIteratorNext(b_iter)))
389    {
390        // Add battery to our list of batteries
391        tracking = _newBatteryFound(battery);
392
393        LogObjectRetainCount("PM::BatteryMatch(M0) me", battery);
394
395        // And install an interest notification on it
396        IOServiceAddInterestNotification(notify, battery,
397                            kIOGeneralInterest, ioregBatteryInterest,
398                            (void *)tracking, &notification_ref);
399
400        LogObjectRetainCount("PM::BatteryMatch(M1) me", battery);
401        LogObjectRetainCount("PM::BatteryMatch(M1) msg_port", notification_ref);
402
403        tracking->msg_port = notification_ref;
404        IOObjectRelease(battery);
405    }
406    InternalEvaluateAssertions();
407    InternalEvalConnections();
408}
409
410
411static void ioregBatteryInterest(
412    void *refcon,
413    io_service_t batt,
414    natural_t messageType,
415    void *messageArgument)
416{
417    IOPMBattery         *changed_batt = (IOPMBattery *)refcon;
418    IOPMBattery         **batt_stats;
419
420    if(kIOPMMessageBatteryStatusHasChanged == messageType)
421    {
422        // Update the arbiter
423        changed_batt->me = (io_registry_entry_t)batt;
424        _batteryChanged(changed_batt);
425
426        LogObjectRetainCount("PM:BatteryInterest(B0) msg_port", changed_batt->msg_port);
427        LogObjectRetainCount("PM:BatteryInterest(B1) msg_port", changed_batt->me);
428
429        batt_stats = _batteries();
430        kernelPowerSourcesDidChange(changed_batt);
431        SystemLoadBatteriesHaveChanged(batt_stats);
432        InternalEvaluateAssertions();
433        InternalEvalConnections();
434    }
435
436    return;
437}
438
439
440__private_extern__ void
441ClockSleepWakeNotification(IOPMSystemPowerStateCapabilities old_cap,
442                           IOPMSystemPowerStateCapabilities new_cap,
443                           uint32_t changeFlags)
444{
445    // Act on the notification before the dark wake to sleep transition
446    if (CAPABILITY_BIT_CHANGED(new_cap, old_cap, kIOPMSystemPowerStateCapabilityCPU) &&
447        BIT_IS_SET(old_cap, kIOPMSystemPowerStateCapabilityCPU) &&
448        BIT_IS_SET(changeFlags, kIOPMSystemCapabilityWillChange))
449    {
450#if !TARGET_OS_EMBEDDED
451        // write SMC Key to re-enable SMC timer
452        _smcWakeTimerPrimer();
453#endif
454
455        // Stash the last sleep time to ignore clock changes before
456        // this sleep is completed.
457        size_t len = sizeof(gLastSleepTime);
458        if (sysctlbyname("kern.sleeptime", &gLastSleepTime, &len, NULL, 0)) {
459            gLastSleepTime.tv_sec = 0;
460            gLastSleepTime.tv_usec = 0;
461        }
462
463        // The next clock resync occuring on wake from sleep shall be marked
464        // as the wake time.
465        gExpectingWakeFromSleepClockResync = true;
466
467#if !TARGET_OS_EMBEDDED
468        if (gLastWakeTimeToken >= 0)
469            notify_set_state(gLastWakeTimeToken, 0);
470        if (gLastSMCS3S0WakeIntervalToken >= 0)
471            notify_set_state(gLastSMCS3S0WakeIntervalToken, 0);
472#endif
473        // tell clients what our timezone offset is
474        broadcastGMTOffset();
475    }
476}
477
478
479/*
480 *
481 * Receives notifications on system sleep and system wake.
482 * This callback is not called for maintenance sleep/wake.
483 */
484static void
485SleepWakeCallback(
486    void            *port,
487    io_service_t    rootdomainservice,
488    natural_t       messageType,
489    void            *acknowledgementToken)
490{
491
492    BatteryTimeRemainingSleepWakeNotification(messageType);
493    PMSettingsSleepWakeNotification(messageType);
494
495    // Log Message to MessageTracer
496
497    // Acknowledge message
498    switch ( messageType ) {
499        case kIOMessageSystemWillSleep:
500            if (isUserActiveRootDomain) {
501                gSleepFromUserWakeTime = CFAbsoluteTimeGetCurrent();
502                userActiveHandleSleep();
503            }
504            // Fall thru
505        case kIOMessageCanSystemSleep:
506            IOAllowPowerChange(_pm_ack_port, (long)acknowledgementToken);
507            break;
508
509        case kIOMessageSystemHasPoweredOn:
510        case kIOMessageSystemWillNotSleep:
511            _set_sleep_revert(true);
512            break;
513
514        default:
515            break;
516    }
517}
518
519/* ESPrefsHaveChanged
520 *
521 * Is the handler that configd calls when someone "applies" new Energy Saver
522 * Preferences. Since the preferences have probably changed, we re-read them
523 * from disk and transmit the new settings to the kernel.
524 */
525static void
526ESPrefsHaveChanged(
527    SCPreferencesRef prefs,
528    SCPreferencesNotification notificationType,
529    void *info)
530{
531    if ((kSCPreferencesNotificationCommit & notificationType) == 0)
532        return;
533
534    if (gESPreferences == prefs)
535    {
536        // Tell ES Prefs listeners that the prefs have changed
537        PMSettingsPrefsHaveChanged();
538        mt2EvaluateSystemSupport();
539#if !TARGET_OS_EMBEDDED
540        UPSLowPowerPrefsHaveChanged();
541        TTYKeepAwakePrefsHaveChanged();
542#endif
543        SystemLoadPrefsHaveChanged();
544    }
545
546    return;
547}
548
549
550/* _ioupsd_exited
551 *
552 * Gets called (by configd) when /usr/libexec/ioupsd exits
553 */
554static void _ioupsd_exited(
555    pid_t           pid,
556    int             status,
557    struct rusage   *rusage,
558    void            *context)
559{
560    if(0 != status)
561    {
562        // ioupsd didn't exit cleanly.
563        syslog(
564            LOG_ERR,
565           "PowerManagement: /usr/libexec/ioupsd(%d) has exited with status %d\n",
566           pid,
567           status);
568
569        // relaunch
570        char *argv[2] = {"/usr/libexec/ioupsd", NULL};
571        _SCDPluginExecCommand(&_ioupsd_exited, 0, 0, 0,
572                              "/usr/libexec/ioupsd", argv);
573    } else {
574        _alreadyRunningIOUPSD = 0;
575    }
576}
577
578
579/* UPSDeviceAdded
580 *
581 * A UPS has been detected running on the system.
582 *
583 */
584static void UPSDeviceAdded(void *refCon, io_iterator_t iterator)
585{
586    io_object_t                 upsDevice = MACH_PORT_NULL;
587
588    while ( (upsDevice = IOIteratorNext(iterator)) )
589    {
590        // If not running, launch the management process ioupsd now.
591        if(!_alreadyRunningIOUPSD) {
592            char *argv[2] = {"/usr/libexec/ioupsd", NULL};
593
594            _alreadyRunningIOUPSD = 1;
595            _SCDPluginExecCommand(&_ioupsd_exited, 0, 0, 0,
596                "/usr/libexec/ioupsd", argv);
597        }
598        IOObjectRelease(upsDevice);
599    }
600}
601
602
603/* timeZoneChangedCallback
604 *
605 * When our timezone offset changes, tell interested drivers.
606 */
607static void
608timeZoneChangedCallBack(
609    CFNotificationCenterRef center,
610    void *observer,
611    CFStringRef notificationName,
612    const void *object,
613    CFDictionaryRef userInfo)
614{
615    if( CFEqual(notificationName, gTZNotificationNameString) )
616    {
617        broadcastGMTOffset();
618    }
619}
620
621
622/* broadcastGMTOffset
623 *
624 * Tell the timezone clients what the seconds offset from GMT is. This info
625 * is delivered via the kernel PMSettings interface.
626 *
627 * Notifications are sent:
628 *    - at boot time
629 *    - when timezone changes
630 *    - at sleep time*
631 *    - at display sleep time*
632 *
633 *    * PM configd does not receive a notification when daylight savings time
634 *      changes. In case the system has entered daylight savings time since
635 *      boot, we re-broadcast the tz offset at sleep and display sleep.
636 */
637static void
638broadcastGMTOffset(void)
639{
640    CFTimeZoneRef               tzr = NULL;
641    CFNumberRef                 n = NULL;
642    int                         secondsOffset = 0;
643
644    CFTimeZoneResetSystem();
645    tzr = CFTimeZoneCopySystem();
646    if(!tzr) return;
647
648    secondsOffset = (int)CFTimeZoneGetSecondsFromGMT(tzr, CFAbsoluteTimeGetCurrent());
649    n = CFNumberCreate(0, kCFNumberIntType, &secondsOffset);
650    if(!n) {
651        goto exit;
652    }
653
654    // Tell the root domain what our timezone's offset from GMT is.
655    // IOPMrootdomain will relay the message on to interested PMSetting clients.
656    _setRootDomainProperty(CFSTR("TimeZoneOffsetSeconds"), n);
657
658exit:
659    if(tzr) CFRelease(tzr);
660    if(n) CFRelease(n);
661    return;
662}
663
664/* lwShutdownCallback
665 *
666 *
667 *
668 * loginwindow shutdown handler
669 *
670 */
671static void lwShutdownCallback(
672    CFMachPortRef port,
673    void *msg,
674    CFIndex size,
675    void *info)
676{
677    mach_msg_header_t   *header = (mach_msg_header_t *)msg;
678    CFNumberRef n = NULL;
679    static bool amidst_shutdown = false;
680    static int consoleShutdownState = kIOPMStateConsoleShutdownNone;
681    static int lastConsoleShutdownState = 0;
682
683    if (header->msgh_id == gCPUPowerNotificationToken)
684    {
685        // System CPU power status has changed
686        SystemLoadCPUPowerHasChanged(NULL);
687    } else if (header->msgh_id == lwNotify.su)
688    {
689        // Loginwindow is logging out to begin a several-minute
690        // software update. We'll suppress the immediately next shoutdown
691        // and logout messages.
692        consoleShutdownState = kIOPMStateConsoleSULogoutInitiated;
693
694    } else if (header->msgh_id == lwNotify.shutdown)
695    {
696        // Loginwindow put a shutdown confirm panel up on screen
697        // The user has not necessarily even clicked on it yet
698        amidst_shutdown = true;
699        consoleShutdownState = kIOPMStateConsoleShutdownPossible;
700
701    } else if (header->msgh_id == lwNotify.restart)
702    {
703        // Loginwindow put a restart confirm panel up on screen
704        // The user has not necessarily even clicked on it yet
705        amidst_shutdown = true;
706        consoleShutdownState = kIOPMStateConsoleShutdownPossible;
707
708    } else if (header->msgh_id == lwNotify.cancel)
709    {
710        amidst_shutdown = false;
711        consoleShutdownState = kIOPMStateConsoleShutdownNone;
712
713    } else if (amidst_shutdown
714            && (header->msgh_id == lwNotify.pointofnoreturn))
715    {
716        // Whatever shutdown or restart that was in progress has succeeded.
717        // All apps are quit, there's no more user input required. We will
718        // hereby disable sleep for the remainder of time spent shutting down
719        // this machine.
720
721        _setRootDomainProperty(CFSTR("System Shutdown"), kCFBooleanTrue);
722        consoleShutdownState = kIOPMStateConsoleShutdownCertain;
723    }
724
725    // Tell interested kernel drivers where we are in the GUI shutdown.
726    if (lastConsoleShutdownState != consoleShutdownState) {
727
728        n = CFNumberCreate(0, kCFNumberIntType, &consoleShutdownState);
729        if (n) {
730            _setRootDomainProperty( CFSTR(kIOPMStateConsoleShutdown), n) ;
731            CFRelease(n);
732        }
733
734        lastConsoleShutdownState = consoleShutdownState;
735    }
736
737
738    return;
739}
740
741
742/* displayPowerStateChange
743 *
744 * displayPowerStateChange gets notified when the display changes power state.
745 * Power state changes look like this:
746 * (1) Full power -> dim
747 * (2) dim -> display sleep
748 * (3) display sleep -> display sleep
749 *
750 * We're interested in state transition 2. On transition to state 2 we
751 * broadcast the system clock's offset from GMT.
752 */
753static void
754displayPowerStateChange(void *ref, io_service_t service, natural_t messageType, void *arg)
755{
756    IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification*) arg;
757    bool prevState = gDisplayIsAsleep;
758
759    switch (messageType)
760    {
761            // Display Wrangler power stateNumber values
762            // 4 Display ON
763            // 3 Display Dim
764            // 2 Display Sleep
765            // 1 Not visible to user
766            // 0 Not visible to user
767
768        case kIOMessageDeviceWillPowerOff:
769            if ( params->stateNumber != 4 )
770            {
771                gDisplayIsAsleep = true;
772            }
773
774            if ( params->stateNumber <= 1)
775            {
776               // Notify a SystemLoad state change when display is completely off
777                SystemLoadDisplayPowerStateHasChanged(gDisplayIsAsleep);
778                // Display is transition from dim to full sleep.
779                broadcastGMTOffset();
780            }
781            break;
782
783        case kIOMessageDeviceHasPoweredOn:
784            if ( params->stateNumber == 4 )
785            {
786                gDisplayIsAsleep = false;
787                SystemLoadDisplayPowerStateHasChanged(gDisplayIsAsleep);
788            }
789
790            break;
791    }
792
793    if (prevState != gDisplayIsAsleep) {
794        logASLDisplayStateChange();
795    }
796}
797
798__private_extern__ bool isDisplayAsleep( )
799{
800    return gDisplayIsAsleep;
801}
802
803/* initializeESPrefsDynamicStore
804 *
805 * Registers a handler that configd calls when someone changes com.apple.PowerManagement.xml
806 */
807static void
808initializeESPrefsDynamicStore(void)
809{
810    gESPreferences = SCPreferencesCreate(
811                    kCFAllocatorDefault,
812                    CFSTR("com.apple.configd.powermanagement"),
813                    CFSTR(kIOPMPrefsPath));
814
815    if (gESPreferences)
816    {
817        SCPreferencesSetCallback(
818                    gESPreferences,
819                    (SCPreferencesCallBack)ESPrefsHaveChanged,
820                    (SCPreferencesContext *)NULL);
821
822        SCPreferencesScheduleWithRunLoop(
823                    gESPreferences,
824                    CFRunLoopGetCurrent(),
825                    kCFRunLoopDefaultMode);
826    }
827
828    return;
829}
830
831
832/* pushNewSleepWakeUUID
833 *
834 * Called (1) At boot, and (2) When kernel PM uses its current UUID.
835 * We pre-allocate the UUID here and send it to the kernel, but the kernel
836 * will not activate it until the _next_ sleep/wake session begins.
837 *
838 * Global gCachedNextSleepWakeUUIDString will always reflect the next
839 * upcoming sleep/wake session UUID; not the current UUID.
840 */
841static void pushNewSleepWakeUUID(void)
842{
843    uuid_t              new_uuid;
844    uuid_string_t       new_uuid_string;
845
846    io_registry_entry_t root_domain = getRootDomain();
847
848    if (IO_OBJECT_NULL == root_domain) {
849        return;
850    }
851
852    uuid_generate(new_uuid);
853    uuid_unparse_upper(new_uuid, new_uuid_string);
854
855    if (gCachedNextSleepWakeUUIDString)
856    {
857        CFRelease(gCachedNextSleepWakeUUIDString);
858
859        gCachedNextSleepWakeUUIDString = NULL;
860    }
861
862    if ((gCachedNextSleepWakeUUIDString = CFStringCreateWithCString(0, new_uuid_string, kCFStringEncodingUTF8)))
863    {
864        IORegistryEntrySetCFProperty(root_domain, CFSTR(kIOPMSleepWakeUUIDKey), gCachedNextSleepWakeUUIDString);
865    }
866    return;
867}
868
869
870static void AppClaimWakeReason(xpc_object_t claim)
871{
872    const char              *id;
873    const char              *reason;
874    xpc_object_t            d;
875
876    if (!claim) {
877        return;
878    }
879
880    id = xpc_dictionary_get_string(claim, "identity"),
881    reason = xpc_dictionary_get_string(claim, "reason"),
882    d = xpc_dictionary_get_value(claim, "description");
883
884    logASLAppWakeReason(id, reason);
885}
886
887static void incoming_XPC_connection(xpc_connection_t peer)
888{
889    xpc_connection_set_event_handler(peer,
890             ^(xpc_object_t event) {
891                 SecTaskRef secTask = NULL;
892                 CFTypeRef  entitled_DarkWakeControl = NULL;
893                 audit_token_t token;
894
895                 xpc_connection_get_audit_token(peer, &token);
896
897                 secTask = SecTaskCreateWithAuditToken(kCFAllocatorDefault, token);
898                 if (secTask) {
899                     entitled_DarkWakeControl = SecTaskCopyValueForEntitlement(secTask, kIOPMDarkWakeControlEntitlement, NULL);
900                 }
901
902                 if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
903
904                     xpc_object_t inEvent;
905
906                     if (entitled_DarkWakeControl
907                         && (inEvent = xpc_dictionary_get_value(event, "claimSystemWakeEvent")))
908                     {
909                         AppClaimWakeReason(inEvent);
910                     }
911                 }
912
913                 if (secTask) {
914                     CFRelease(secTask);
915                 }
916                 if (entitled_DarkWakeControl) {
917                     CFRelease(entitled_DarkWakeControl);
918                 }
919             });
920
921    xpc_connection_resume(peer);
922    return;
923}
924
925static void xpc_register(void)
926{
927    xpc_connection_t        connection;
928
929    connection = xpc_connection_create_mach_service(
930                                                    "com.apple.iokit.powerdxpc",
931                                                    dispatch_get_main_queue(),
932                                                    XPC_CONNECTION_MACH_SERVICE_LISTENER);
933
934    xpc_connection_set_target_queue(connection, dispatch_get_main_queue());
935
936    xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
937            xpc_type_t type = xpc_get_type(event);
938            if (type == XPC_TYPE_CONNECTION) {
939                incoming_XPC_connection((xpc_connection_t)event);
940            }
941        });
942
943    xpc_connection_resume(connection);
944}
945
946
947static boolean_t
948pm_mig_demux(
949    mach_msg_header_t * request,
950    mach_msg_header_t * reply)
951{
952    mach_dead_name_notification_t *deadRequest =
953                    (mach_dead_name_notification_t *)request;
954    boolean_t processed = FALSE;
955
956    processed = powermanagement_server(request, reply);
957
958    if (processed)
959        return true;
960
961    if (MACH_NOTIFY_DEAD_NAME == request->msgh_id)
962    {
963        __MACH_PORT_DEBUG(true, "pm_mig_demux: Dead name port should have 1+ send right(s)", deadRequest->not_port);
964
965        PMConnectionHandleDeadName(deadRequest->not_port);
966
967        __MACH_PORT_DEBUG(true, "pm_mig_demux: Deallocating dead name port", deadRequest->not_port);
968        mach_port_deallocate(mach_task_self(), deadRequest->not_port);
969
970        reply->msgh_bits            = 0;
971        reply->msgh_remote_port     = MACH_PORT_NULL;
972
973        return TRUE;
974    }
975
976    // mig request is not in our subsystem range!
977    // generate error reply packet
978    reply->msgh_bits        = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request->msgh_bits), 0);
979    reply->msgh_remote_port = request->msgh_remote_port;
980    reply->msgh_size        = sizeof(mig_reply_error_t);    /* Minimal size */
981    reply->msgh_local_port  = MACH_PORT_NULL;
982    reply->msgh_id          = request->msgh_id + 100;
983    ((mig_reply_error_t *)reply)->NDR = NDR_record;
984    ((mig_reply_error_t *)reply)->RetCode = MIG_BAD_ID;
985
986    return processed;
987}
988
989
990
991static void
992mig_server_callback(CFMachPortRef port, void *msg, CFIndex size, void *info)
993{
994    mig_reply_error_t * bufRequest = msg;
995    mig_reply_error_t * bufReply = CFAllocatorAllocate(
996        NULL, _powermanagement_subsystem.maxsize, 0);
997    mach_msg_return_t   mr;
998    int                 options;
999
1000    __MACH_PORT_DEBUG(true, "mig_server_callback", serverPort);
1001
1002    /* we have a request message */
1003    (void) pm_mig_demux(&bufRequest->Head, &bufReply->Head);
1004
1005    if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
1006         (bufReply->RetCode != KERN_SUCCESS)) {
1007
1008        if (bufReply->RetCode == MIG_NO_REPLY) {
1009            /*
1010             * This return code is a little tricky -- it appears that the
1011             * demux routine found an error of some sort, but since that
1012             * error would not normally get returned either to the local
1013             * user or the remote one, we pretend it's ok.
1014             */
1015            goto out;
1016
1017        }
1018
1019        /*
1020         * destroy any out-of-line data in the request buffer but don't destroy
1021         * the reply port right (since we need that to send an error message).
1022         */
1023        bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
1024        mach_msg_destroy(&bufRequest->Head);
1025    }
1026
1027    if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) {
1028        /* no reply port, so destroy the reply */
1029        if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
1030            mach_msg_destroy(&bufReply->Head);
1031        }
1032        goto out;
1033    }
1034
1035    /*
1036     * send reply.
1037     *
1038     * We don't want to block indefinitely because the client
1039     * isn't receiving messages from the reply port.
1040     * If we have a send-once right for the reply port, then
1041     * this isn't a concern because the send won't block.
1042     * If we have a send right, we need to use MACH_SEND_TIMEOUT.
1043     * To avoid falling off the kernel's fast RPC path unnecessarily,
1044     * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
1045     */
1046
1047    options = MACH_SEND_MSG;
1048    if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1049        options |= MACH_SEND_TIMEOUT;
1050    }
1051    mr = mach_msg(&bufReply->Head,          /* msg */
1052              options,                      /* option */
1053              bufReply->Head.msgh_size,     /* send_size */
1054              0,                            /* rcv_size */
1055              MACH_PORT_NULL,               /* rcv_name */
1056              MACH_MSG_TIMEOUT_NONE,        /* timeout */
1057              MACH_PORT_NULL);              /* notify */
1058
1059
1060    /* Has a message error occurred? */
1061    switch (mr) {
1062        case MACH_SEND_INVALID_DEST:
1063        case MACH_SEND_TIMED_OUT:
1064            /* the reply can't be delivered, so destroy it */
1065            mach_msg_destroy(&bufReply->Head);
1066            break;
1067
1068        default :
1069            /* Includes success case.  */
1070            break;
1071    }
1072
1073
1074out:
1075    CFAllocatorDeallocate(NULL, bufReply);
1076    return;
1077
1078}
1079
1080/* dynamicStoreNotifyCallBack
1081 *
1082 * Changed Keys in dynamic store
1083 *
1084 */
1085__private_extern__
1086void dynamicStoreNotifyCallBack(
1087    SCDynamicStoreRef   store,
1088    CFArrayRef          changedKeys,
1089    void                *info)
1090{
1091    CFRange range = CFRangeMake(0,
1092                CFArrayGetCount(changedKeys));
1093
1094    // Check for Console user change
1095    if (gConsoleNotifyKey
1096        && CFArrayContainsValue(changedKeys,
1097                                range,
1098                                gConsoleNotifyKey))
1099    {
1100#if !TARGET_OS_EMBEDDED
1101        SystemLoadUserStateHasChanged();
1102#endif
1103    }
1104
1105    return;
1106}
1107
1108kern_return_t _io_pm_set_value_int(
1109    mach_port_t   server,
1110    audit_token_t token,
1111    int           selector,
1112    int           inValue,
1113    int           *result)
1114{
1115    uid_t   callerUID;
1116    audit_token_to_au32(token, NULL, NULL, NULL, &callerUID, 0, 0, NULL, NULL);
1117
1118    *result = kIOReturnSuccess;
1119    switch (selector) {
1120    case kIOPMSetNoPoll:
1121        BatterySetNoPoll(inValue ? true:false);
1122        break;
1123
1124    case kIOPMSetAssertionActivityLog:
1125        setAssertionActivityLog(inValue);
1126        break;
1127
1128    case kIOPMSetAssertionActivityAggregate:
1129        setAssertionActivityAggregate(inValue);
1130        break;
1131
1132    case kIOPMSetReservePowerMode:
1133        if (!auditTokenHasEntitlement(token, kIOPMReservePwrCtrlEntitlement))
1134            *result = kIOReturnNotPrivileged;
1135        else
1136            *result = setReservePwrMode(inValue);
1137
1138    default:
1139        break;
1140    }
1141    return KERN_SUCCESS;
1142}
1143
1144
1145kern_return_t _io_pm_get_value_int(
1146    mach_port_t   server,
1147    audit_token_t token,
1148    int           selector,
1149    int           *outValue)
1150{
1151    uid_t   callerUID;
1152    audit_token_to_au32(token, NULL, NULL, NULL, &callerUID, 0, 0, NULL, NULL);
1153
1154    *outValue = 0;
1155
1156    switch(selector)
1157    {
1158#if !TARGET_OS_EMBEDDED
1159      case kIOPMGetSilentRunningInfo:
1160         if ( smcSilentRunningSupport( ))
1161            *outValue = 1;
1162         else
1163             *outValue = 0;
1164         break;
1165
1166     case kIOPMMT2Bookmark:
1167            if (0 == callerUID)
1168            {
1169                mt2PublishReports();
1170                *outValue = 0;
1171            } else {
1172                *outValue = 1;
1173            }
1174          break;
1175    case kIOPMDarkWakeThermalEventCount:
1176            *outValue = _darkWakeThermalEventCount;
1177        break;
1178#if TCPKEEPALIVE
1179    case kIOPMTCPKeepAliveExpirationOverride:
1180            if (gTCPKeepAlive) {
1181                *outValue = gTCPKeepAlive->overrideSec;
1182            }
1183        break;
1184
1185    case kIOPMTCPKeepAliveIsActive:
1186            if (gTCPKeepAlive) {
1187                *outValue = (getTCPKeepAliveState(NULL, 0) == kActive) ? true : false;
1188            }
1189            break;
1190#endif
1191
1192#endif
1193      default:
1194         *outValue = 0;
1195         break;
1196
1197    }
1198    return KERN_SUCCESS;
1199}
1200
1201
1202
1203kern_return_t _io_pm_force_active_settings(
1204    mach_port_t                 server,
1205    audit_token_t               token,
1206    vm_offset_t                 settings_ptr,
1207    mach_msg_type_number_t      settings_len,
1208    int                         *result)
1209{
1210    void                    *settings_buf = (void *)settings_ptr;
1211    CFDictionaryRef         force_settings = NULL;
1212    uid_t                   callerUID;
1213
1214    audit_token_to_au32(token, NULL, &callerUID, NULL, NULL, NULL, NULL, NULL, NULL);
1215
1216    if (0 != callerUID) {
1217        // Caller must be root
1218        *result = kIOReturnNotPrivileged;
1219    } else {
1220        force_settings = (CFDictionaryRef)IOCFUnserialize(settings_buf, 0, 0, 0);
1221
1222        if(isA_CFDictionary(force_settings))
1223        {
1224            *result = _activateForcedSettings(force_settings);
1225        } else {
1226            *result = kIOReturnBadArgument;
1227        }
1228
1229        if(force_settings)
1230        {
1231            CFRelease(force_settings);
1232        }
1233    }
1234
1235    // deallocate client's memory
1236    vm_deallocate(mach_task_self(), (vm_address_t)settings_ptr, settings_len);
1237
1238    return KERN_SUCCESS;
1239}
1240
1241kern_return_t _io_pm_set_active_profile(
1242    mach_port_t         server,
1243    audit_token_t       token,
1244    vm_offset_t         profiles_ptr,
1245    mach_msg_type_number_t    profiles_len,
1246    int                 *result)
1247{
1248    void                *profiles_buf = (void *)profiles_ptr;
1249    CFDictionaryRef     power_profiles = NULL;
1250    uid_t               callerUID;
1251    gid_t               callerGID;
1252
1253    audit_token_to_au32(token, NULL, &callerUID, &callerGID, NULL, NULL, NULL, NULL, NULL);
1254
1255    power_profiles = (CFDictionaryRef)IOCFUnserialize(profiles_buf, 0, 0, 0);
1256    if(isA_CFDictionary(power_profiles)) {
1257        *result = _IOPMSetActivePowerProfilesRequiresRoot(power_profiles, callerUID, callerGID);
1258        CFRelease(power_profiles);
1259    } else if(power_profiles) {
1260        CFRelease(power_profiles);
1261    }
1262
1263    // deallocate client's memory
1264    vm_deallocate(mach_task_self(), (vm_address_t)profiles_ptr, profiles_len);
1265
1266    return KERN_SUCCESS;
1267}
1268
1269
1270
1271
1272/* initializeInteresteNotifications
1273 *
1274 * Sets up the notification of general interest from the RootDomain
1275 */
1276static void
1277initializeInterestNotifications()
1278{
1279    IONotificationPortRef       notify_port = 0;
1280    io_iterator_t               battery_iter = 0;
1281    io_iterator_t               display_iter = 0;
1282    CFRunLoopSourceRef          rlser = 0;
1283
1284    kern_return_t               kr;
1285
1286    /* Notifier */
1287    notify_port = IONotificationPortCreate(0);
1288    rlser = IONotificationPortGetRunLoopSource(notify_port);
1289    if(!rlser) return;
1290    CFRunLoopAddSource(CFRunLoopGetCurrent(), rlser, kCFRunLoopDefaultMode);
1291
1292
1293    kr = IOServiceAddMatchingNotification(
1294                                notify_port,
1295                                kIOFirstMatchNotification,
1296                                IOServiceMatching("IOPMPowerSource"),
1297                                ioregBatteryMatch,
1298                                (void *)notify_port,
1299                                &battery_iter);
1300    if(KERN_SUCCESS == kr)
1301    {
1302        // Install notifications on existing instances.
1303        ioregBatteryMatch((void *)notify_port, battery_iter);
1304    }
1305
1306    kr = IOServiceAddMatchingNotification(
1307                                notify_port,
1308                                kIOFirstMatchNotification,
1309                                IOServiceMatching("IODisplayWrangler"),
1310                                displayMatched,
1311                                (void *)notify_port,
1312                                &display_iter);
1313    if(KERN_SUCCESS == kr)
1314    {
1315        // Install notifications on existing instances.
1316        displayMatched((void *)notify_port, display_iter);
1317    }
1318    else {
1319        asl_log(NULL, NULL, ASL_LEVEL_ERR,
1320                "Failed to match DisplayWrangler(0x%x)\n", kr);
1321    }
1322
1323    // Listen for Power devices and Battery Systems to start ioupsd
1324    initializeHIDInterestNotifications(kIOPowerDeviceUsageKey, notify_port);
1325    initializeHIDInterestNotifications(kIOBatterySystemUsageKey, notify_port);
1326}
1327
1328static void
1329initializeHIDInterestNotifications(int usagePage,
1330                                   IONotificationPortRef notify_port)
1331{
1332    CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOHIDDeviceKey);
1333    if (!matchingDict) {
1334        return;
1335    }
1336
1337    // We need to box the Usage Page value up into a CFNumber... sorry bout that
1338    CFNumberRef cfUsagePageKey = CFNumberCreate(kCFAllocatorDefault,
1339                                                kCFNumberIntType,
1340                                                &usagePage);
1341    if (!cfUsagePageKey) {
1342        CFRelease(matchingDict);
1343        return;
1344    }
1345
1346    CFDictionarySetValue(matchingDict,
1347                         CFSTR(kIOHIDPrimaryUsagePageKey),
1348                         cfUsagePageKey);
1349    CFRelease(cfUsagePageKey);
1350
1351
1352    // Now set up a notification to be called when a device is first matched by
1353    // I/O Kit. Note that this will not catch any devices that were already
1354    // plugged in so we take care of those later.
1355    kern_return_t kr =
1356            IOServiceAddMatchingNotification(notify_port,
1357                                             kIOFirstMatchNotification,
1358                                             matchingDict,
1359                                             UPSDeviceAdded,
1360                                             NULL,
1361                                             &_ups_added_noteref);
1362
1363    matchingDict = 0; // reference consumed by AddMatchingNotification
1364    if ( kr == kIOReturnSuccess ) {
1365        // Check for existing matching devices and launch ioupsd if present.
1366        UPSDeviceAdded( NULL, _ups_added_noteref);
1367    }
1368}
1369
1370/* initializeTimezoneChangeNotifications
1371 *
1372 * Sets up the tz notifications that we re-broadcast to all interested
1373 * kernel clients listening via PMSettings
1374 */
1375static void
1376initializeTimezoneChangeNotifications(void)
1377{
1378    CFNotificationCenterRef         distNoteCenter = NULL;
1379
1380    gTZNotificationNameString = CFStringCreateWithCString(
1381                        kCFAllocatorDefault,
1382                        "NSSystemTimeZoneDidChangeDistributedNotification",
1383                        kCFStringEncodingMacRoman);
1384
1385#if TARGET_OS_EMBEDDED
1386    distNoteCenter = CFNotificationCenterGetDarwinNotifyCenter();
1387#else
1388    distNoteCenter = CFNotificationCenterGetDistributedCenter();
1389#endif
1390    if(distNoteCenter)
1391    {
1392        CFNotificationCenterAddObserver(
1393                       distNoteCenter,
1394                       NULL,
1395                       timeZoneChangedCallBack,
1396                       gTZNotificationNameString,
1397                       NULL,
1398                       CFNotificationSuspensionBehaviorDeliverImmediately);
1399    }
1400
1401    // Boot time - tell clients what our timezone offset is
1402    broadcastGMTOffset();
1403}
1404
1405static void initializeCalendarResyncNotification(void)
1406{
1407    CFMachPortRef               mpref = NULL;
1408    CFRunLoopSourceRef          mpsrc = NULL;
1409    mach_port_t                 nport, tport;
1410    kern_return_t               result;
1411
1412    result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &nport);
1413    if (result != KERN_SUCCESS) {
1414        goto exit;
1415    }
1416    result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &tport);
1417    if (result != KERN_SUCCESS) {
1418        goto exit;
1419    }
1420    result = mach_port_move_member(mach_task_self(), tport, nport);
1421    if (result != KERN_SUCCESS) {
1422        goto exit;
1423    }
1424    result = host_request_notification(mach_host_self(), HOST_NOTIFY_CALENDAR_CHANGE, tport);
1425    if (result != KERN_SUCCESS) {
1426        goto exit;
1427    }
1428
1429    mpref = _SC_CFMachPortCreateWithPort("PowerManagement/calendarResync", tport, calendarRTCDidResync, NULL);
1430    if (mpref) {
1431        mpsrc = CFMachPortCreateRunLoopSource(0, mpref, 0);
1432        if (mpsrc) {
1433            CFRunLoopAddSource(CFRunLoopGetCurrent(), mpsrc, kCFRunLoopDefaultMode);
1434            CFRelease(mpsrc);
1435        }
1436        CFRelease(mpref);
1437    }
1438
1439exit:
1440    return;
1441}
1442
1443static void calendarRTCDidResync_getSMCWakeInterval(void)
1444{
1445#if !TARGET_OS_EMBEDDED
1446    uint16_t            wakeup_smc_result = 0;
1447    IOReturn            ret = kIOReturnSuccess;
1448#endif
1449    CFAbsoluteTime      lastWakeTime;
1450    struct timeval      lastSleepTime;
1451    size_t              len = sizeof(struct timeval);
1452
1453    // Capture this as early as possible
1454    lastWakeTime = CFAbsoluteTimeGetCurrent();
1455
1456    if (!gExpectingWakeFromSleepClockResync) {
1457        // This is a non-wake-from-sleep clock resync, so we'll ignore it.
1458        goto exit;
1459    }
1460
1461    if (sysctlbyname("kern.sleeptime", &lastSleepTime, &len, NULL, 0) ||
1462        ((gLastSleepTime.tv_sec  == lastSleepTime.tv_sec) &&
1463         (gLastSleepTime.tv_usec == lastSleepTime.tv_usec)))
1464    {
1465        // This is a clock resync after sleep has started but before
1466        // platform sleep.
1467        goto exit;
1468    }
1469
1470    // if needed, init standalone memory for last wake time data
1471    if (!gLastSMCS3S0WakeInterval) {
1472        size_t bufSize;
1473
1474        bufSize = sizeof(*gLastWakeTime) + sizeof(*gLastSMCS3S0WakeInterval);
1475        if (0 != vm_allocate(mach_task_self(), (void*)&gLastWakeTime,
1476                             bufSize, VM_FLAGS_ANYWHERE)) {
1477            return;
1478        }
1479        gLastSMCS3S0WakeInterval = gLastWakeTime + 1;
1480    } else {
1481        // validate pointers allocated earlier
1482        if (!gLastWakeTime || !gLastSMCS3S0WakeInterval)
1483            return;
1484    }
1485
1486    // This is a wake-from-sleep resync, so commit the last wake time
1487    *gLastWakeTime = lastWakeTime;
1488    *gLastSMCS3S0WakeInterval = 0;
1489    gExpectingWakeFromSleepClockResync = false;
1490
1491    // Re-enable battery time remaining calculations
1492    (void) BatteryTimeRemainingRTCDidResync();
1493
1494#if !TARGET_OS_EMBEDDED
1495    if (!gSMCSupportsWakeupTimer) {
1496        // This system's SMC doesn't support a wakeup time, so we're done
1497        goto exit;
1498    }
1499
1500    if (gLastWakeTimeToken < 0)
1501        notify_register_check(kIOPMLastWakeTimeString, &gLastWakeTimeToken);
1502    if (gLastSMCS3S0WakeIntervalToken < 0)
1503        notify_register_check(kIOPMLastWakeTimeSMCDataString, &gLastSMCS3S0WakeIntervalToken);
1504
1505    // Read SMC key for precise timing between when the wake event physically occurred
1506    // and now (i.e. the moment we read the key).
1507    // - SMC key returns the delta in tens of milliseconds
1508    ret = _smcWakeTimerGetResults(&wakeup_smc_result);
1509    if ((ret != kIOReturnSuccess) || (wakeup_smc_result == 0))
1510    {
1511        if (kIOReturnNotFound == ret) {
1512            gSMCSupportsWakeupTimer = false;
1513        }
1514        goto exit;
1515    }
1516    // re-sample the current time closer to the SMC key read
1517    *gLastWakeTime = CFAbsoluteTimeGetCurrent();
1518
1519    // convert 10x msecs to (double)seconds
1520    *gLastSMCS3S0WakeInterval = ((double)wakeup_smc_result / 100.0);
1521
1522    // And we adjust backwards to determine the real time of physical wake.
1523    *gLastWakeTime -= *gLastSMCS3S0WakeInterval;
1524
1525    if (gLastWakeTimeToken >= 0) {
1526        union {
1527            uint64_t        u64;
1528            CFAbsoluteTime  time;
1529        } nstate;
1530        __Check_Compile_Time(sizeof(nstate.time) <= sizeof(nstate.u64));
1531
1532        nstate.u64 = 0;
1533        nstate.time = *gLastWakeTime;
1534        notify_set_state(gLastWakeTimeToken, nstate.u64);
1535    }
1536    if (gLastSMCS3S0WakeIntervalToken >= 0)
1537        notify_set_state(gLastSMCS3S0WakeIntervalToken, wakeup_smc_result);
1538#endif
1539exit:
1540    return;
1541}
1542
1543static void calendarRTCDidResync(CFMachPortRef port, void *msg, CFIndex size, void *info)
1544{
1545    mach_msg_header_t   *header = (mach_msg_header_t *)msg;
1546
1547    if (!header || HOST_CALENDAR_CHANGED_REPLYID != header->msgh_id) {
1548        return;
1549    }
1550
1551    // renew our request for calendar change notification
1552    (void) host_request_notification(mach_host_self(), HOST_NOTIFY_CALENDAR_CHANGE,
1553                                     header->msgh_local_port);
1554
1555    calendarRTCDidResync_getSMCWakeInterval();
1556    AutoWakeCalendarChange();
1557
1558    return;
1559}
1560
1561/* MIG CALL
1562 * Returns last wake time to a querulous process
1563 */
1564kern_return_t _io_pm_last_wake_time(
1565    mach_port_t             server,
1566    vm_offset_t             *out_wake_data,
1567    mach_msg_type_number_t  *out_wake_len,
1568    vm_offset_t             *out_delta_data,
1569    mach_msg_type_number_t  *out_delta_len,
1570    int                     *return_val)
1571{
1572    *out_wake_len = 0;
1573    *out_delta_len = 0;
1574    *return_val = kIOReturnInvalid;
1575
1576    if (gExpectingWakeFromSleepClockResync) {
1577        *return_val = kIOReturnNotReady;
1578        return KERN_SUCCESS;
1579    }
1580
1581#if !TARGET_OS_EMBEDDED
1582    if (!gSMCSupportsWakeupTimer) {
1583        *return_val = kIOReturnNotFound;
1584        return KERN_SUCCESS;
1585    };
1586#endif
1587
1588    *out_wake_data = (vm_offset_t)gLastWakeTime;
1589    *out_wake_len = sizeof(*gLastWakeTime);
1590    *out_delta_data = (vm_offset_t)gLastSMCS3S0WakeInterval;
1591    *out_delta_len = sizeof(*gLastSMCS3S0WakeInterval);
1592
1593    *return_val = kIOReturnSuccess;
1594
1595    return KERN_SUCCESS;
1596}
1597
1598
1599/* displayMatched
1600 *
1601 * Notification fires when IODisplayWranger object is created in the IORegistry.
1602 *
1603 */
1604static void displayMatched(
1605    void *note_port_in,
1606    io_iterator_t iter)
1607{
1608    IONotificationPortRef       note_port = (IONotificationPortRef)note_port_in;
1609    io_service_t                wrangler = MACH_PORT_NULL;
1610    io_object_t                 dimming_notification_object = MACH_PORT_NULL;
1611
1612    if((wrangler = (io_registry_entry_t)IOIteratorNext(iter)))
1613    {
1614        IOServiceAddInterestNotification(
1615                    note_port,
1616                    wrangler,
1617                    kIOGeneralInterest,
1618                    displayPowerStateChange,
1619                    NULL,
1620                    &dimming_notification_object);
1621
1622        IOObjectRelease(wrangler);
1623    }
1624
1625}
1626
1627
1628static void
1629initializeShutdownNotifications(void)
1630{
1631    CFMachPortRef       gNotifyMachPort = NULL;
1632    CFRunLoopSourceRef  gNotifyMachPortRLS = NULL;
1633    mach_port_t         our_port = MACH_PORT_NULL;
1634
1635    // Tell the kernel that we are NOT shutting down at the moment, since
1636    // configd is just launching now.
1637    // Why: if configd crashed with "System Shutdown" == kCFbooleanTrue, reset
1638    // it now as the situation may no longer apply.
1639    _setRootDomainProperty(CFSTR("System Shutdown"), kCFBooleanFalse);
1640
1641    /* * * * * * * * * * * * * */
1642
1643    // Sneak in our registration for CPU power notifications here; to piggy-back
1644    // with the other mach port registrations for LW.
1645    notify_register_mach_port(
1646                        kIOPMCPUPowerNotificationKey,
1647                        &our_port,
1648                        0, /* flags */
1649                        &gCPUPowerNotificationToken);
1650
1651
1652    notify_register_mach_port(
1653                        kLWShutdowntInitiated,
1654                        &our_port,
1655                        NOTIFY_REUSE, /* flags */
1656                        &lwNotify.shutdown);
1657
1658    notify_register_mach_port(
1659                        kLWRestartInitiated,
1660                        &our_port,
1661                        NOTIFY_REUSE, /* flags */
1662                        &lwNotify.restart);
1663
1664    notify_register_mach_port(
1665                        kLWLogoutCancelled,
1666                        &our_port,
1667                        NOTIFY_REUSE, /* flags */
1668                        &lwNotify.cancel);
1669
1670    notify_register_mach_port(
1671                        kLWLogoutPointOfNoReturn,
1672                        &our_port,
1673                        NOTIFY_REUSE, /* flags */
1674                        &lwNotify.pointofnoreturn);
1675    notify_register_mach_port(
1676                        kLWSULogoutInitiated,
1677                        &our_port,
1678                        NOTIFY_REUSE, /* flags */
1679                        &lwNotify.su);
1680
1681    /* * * * * * * * * * * * * */
1682
1683    gNotifyMachPort = _SC_CFMachPortCreateWithPort(
1684                                "PowerManagement/shutdown",
1685                                our_port,
1686                                lwShutdownCallback,
1687                                NULL);
1688
1689    if (gNotifyMachPort) {
1690        gNotifyMachPortRLS = CFMachPortCreateRunLoopSource(0, gNotifyMachPort, 0);
1691        if (gNotifyMachPortRLS) {
1692            CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotifyMachPortRLS, kCFRunLoopDefaultMode);
1693            CFRelease(gNotifyMachPortRLS);
1694        }
1695        CFRelease(gNotifyMachPort);
1696    }
1697}
1698
1699#if !TARGET_OS_EMBEDDED
1700static void handleDWThermalMsg(CFStringRef wakeType)
1701{
1702    CFMutableDictionaryRef options = NULL;
1703
1704    if (wakeType == NULL)
1705        getPlatformWakeReason(NULL, &wakeType);
1706
1707    if ( (isA_BTMtnceWake() || isA_SleepSrvcWake()) && !isA_NotificationDisplayWake() &&
1708               (CFEqual(wakeType, kIOPMRootDomainWakeTypeMaintenance) ||
1709                        CFEqual(wakeType, kIOPMRootDomainWakeTypeSleepService))
1710#if TCPKEEPALIVE
1711            && !((getTCPKeepAliveState(NULL, 0) == kActive) && checkForActivesByType(kInteractivePushServiceType)) ) {
1712#else
1713        ) {
1714#endif
1715
1716        // If system woke up for PowerNap and system is in a power nap wake, without any notifications
1717        // being displayed, then let system go to sleep
1718        options = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks,
1719                            &kCFTypeDictionaryValueCallBacks);
1720        if (options) {
1721            CFDictionarySetValue(options, CFSTR("Sleep Reason"), CFSTR(kIOPMDarkWakeThermalEmergencyKey));
1722        }
1723        IOPMSleepSystemWithOptions(getRootDomainConnect(), options);
1724        if (options) CFRelease(options);
1725    }
1726    else {
1727        // For all other cases, let system run in non-silent running mode
1728        _unclamp_silent_running(true);
1729        logASLMessageIgnoredDWTEmergency();
1730    }
1731}
1732#endif
1733
1734
1735static void
1736RootDomainInterest(
1737    void *refcon,
1738    io_service_t root_domain,
1739    natural_t messageType,
1740    void *messageArgument)
1741{
1742    static CFStringRef  _uuidString = NULL;
1743#if !TARGET_OS_EMBEDDED
1744    CFStringRef wakeReason = NULL, wakeType = NULL;
1745#endif
1746
1747    if (messageType == kIOPMMessageDriverAssertionsChanged)
1748    {
1749        CFNumberRef     driverAssertions = 0;
1750        uint32_t        _driverAssertions = 0;
1751
1752        // Read driver assertion status
1753        driverAssertions = IORegistryEntryCreateCFProperty(getRootDomain(), CFSTR(kIOPMAssertionsDriverKey), 0, 0);
1754
1755        if (driverAssertions) {
1756            CFNumberGetValue(driverAssertions, kCFNumberIntType, &_driverAssertions);
1757            _PMAssertionsDriverAssertionsHaveChanged(_driverAssertions);
1758            CFRelease(driverAssertions);
1759        }
1760    }
1761
1762    if (messageType == kIOPMMessageSystemPowerEventOccurred)
1763    {
1764        // Let System Events know about just-occurred thermal state change
1765
1766        PMSystemEventsRootDomainInterest();
1767    }
1768
1769#if !TARGET_OS_EMBEDDED
1770    if(messageType == kIOPMMessageDarkWakeThermalEmergency)
1771    {
1772        mt2RecordThermalEvent(kThermalStateSleepRequest);
1773        _darkWakeThermalEventCount++;
1774
1775        getPlatformWakeReason(&wakeReason, &wakeType);
1776        if (CFEqual(wakeReason, CFSTR("")) && CFEqual(wakeType, CFSTR("")))
1777        {
1778            // Thermal emergency msg is received too early before wake type is
1779            // determined. Delay the handler for a short handler until we know
1780            // the wake type
1781            if (gDWTMsgDispatch)
1782                dispatch_suspend(gDWTMsgDispatch);
1783            else {
1784                gDWTMsgDispatch = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0,
1785                        0, dispatch_get_main_queue());
1786                dispatch_source_set_event_handler(gDWTMsgDispatch, ^{
1787                    handleDWThermalMsg(NULL);
1788                });
1789
1790                dispatch_source_set_cancel_handler(gDWTMsgDispatch, ^{
1791                    if (gDWTMsgDispatch) {
1792                        dispatch_release(gDWTMsgDispatch);
1793                        gDWTMsgDispatch = 0;
1794                    }
1795                });
1796            }
1797
1798            dispatch_source_set_timer(gDWTMsgDispatch,
1799                    dispatch_walltime(NULL, kDWTMsgHandlerDelay * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0);
1800            dispatch_resume(gDWTMsgDispatch);
1801        }
1802        else
1803        {
1804            handleDWThermalMsg(wakeType);
1805            CFRunLoopPerformBlock(_getPMRunLoop(), kCFRunLoopDefaultMode,
1806                        ^{ logASLAssertionTypeSummary(kInteractivePushServiceType);});
1807            CFRunLoopWakeUp(_getPMRunLoop());
1808        }
1809
1810    }
1811#endif
1812
1813    if (messageType == kIOPMMessageFeatureChange)
1814    {
1815        // Let PMSettings code know that some settings may have been
1816        // added or removed.
1817
1818        PMSettingsSupportedPrefsListHasChanged();
1819    }
1820
1821    if (messageType == kIOPMMessageSleepWakeUUIDChange)
1822    {
1823        if (kIOPMMessageSleepWakeUUIDSet == messageArgument)
1824        {
1825            // We keep a copy of the newly published UUID string
1826            _uuidString = IOPMSleepWakeCopyUUID();
1827
1828            // xnu kernel PM has just published a sleep/Wake UUID.
1829            // We must replenish it with a new one (which we generate in user space)
1830            // Kernel PM will use the UUID we provide here on the next sleep/wake event.
1831            pushNewSleepWakeUUID();
1832
1833        } else
1834        if (kIOPMMessageSleepWakeUUIDCleared == messageArgument)
1835        {
1836            // UUID cleared
1837            if (_uuidString) {
1838                // We're ready to parse out the newly acquired Power log and
1839                // package events that pertain to the current UUID
1840                CFRelease(_uuidString);
1841                _uuidString = NULL;
1842            }
1843
1844            // The kernel will have begun using its cached UUID (the one that we just stored)
1845            // for its power events log. We need to replenish its (now empty) cache with another
1846            // UUID, which in turn will get used when the current one expires
1847
1848            pushNewSleepWakeUUID();
1849
1850        }
1851    }
1852
1853    if (messageType == kIOPMMessageUserIsActiveChanged)
1854    {
1855        userActiveHandleRootDomainActivity();
1856    }
1857}
1858
1859static void
1860initializeRootDomainInterestNotifications(void)
1861{
1862    IONotificationPortRef       note_port = MACH_PORT_NULL;
1863    CFRunLoopSourceRef          runLoopSrc = NULL;
1864    io_service_t                root_domain = MACH_PORT_NULL;
1865    io_object_t                 notification_object = MACH_PORT_NULL;
1866    IOReturn                    ret;
1867
1868    root_domain = IORegistryEntryFromPath(kIOMasterPortDefault,
1869                            kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
1870
1871    if(!root_domain) return;
1872
1873    note_port = IONotificationPortCreate(MACH_PORT_NULL);
1874    if(!note_port) goto exit;
1875
1876    ret = IOServiceAddInterestNotification(note_port, root_domain,
1877                kIOGeneralInterest, RootDomainInterest,
1878                NULL, &notification_object);
1879    if (ret != kIOReturnSuccess) goto exit;
1880
1881    runLoopSrc = IONotificationPortGetRunLoopSource(note_port);
1882
1883    if (runLoopSrc)
1884    {
1885        CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSrc, kCFRunLoopDefaultMode);
1886    }
1887
1888exit:
1889    // Do not release notification_object, would uninstall notification
1890    // Do not release runLoopSrc because it's 'owned' by note_port, and both
1891    // must be kept around to receive this notification
1892    if(MACH_PORT_NULL != root_domain) IOObjectRelease(root_domain);
1893}
1894
1895#if !TARGET_OS_EMBEDDED
1896static void initializeUserNotifications(void)
1897{
1898    SCDynamicStoreRef   localStore = _getSharedPMDynamicStore();
1899    CFArrayRef          keys = NULL;
1900
1901    gConsoleNotifyKey = SCDynamicStoreKeyCreateConsoleUser(NULL);
1902    if (gConsoleNotifyKey)
1903    {
1904        keys = CFArrayCreate(NULL, (const void **)&gConsoleNotifyKey,
1905                                1, &kCFTypeArrayCallBacks);
1906
1907        if (keys) {
1908            SCDynamicStoreSetNotificationKeys(localStore, keys, NULL);
1909            CFRelease(keys);
1910        }
1911    }
1912
1913    SystemLoadUserStateHasChanged();
1914}
1915
1916static void enableSleepWakeWdog()
1917{
1918    io_service_t                rootDomainService = IO_OBJECT_NULL;
1919    io_connect_t                rotDomainConnect = IO_OBJECT_NULL;
1920    kern_return_t               kr = 0;
1921    IOReturn                    ret;
1922
1923    // Check if system supports NTS
1924    if (IONoteToSelfSupported() == false)
1925        return;
1926
1927    // Find it
1928    rootDomainService = getRootDomain();
1929    if (IO_OBJECT_NULL == rootDomainService) {
1930        goto exit;
1931    }
1932
1933    // Open it
1934    kr = IOServiceOpen(rootDomainService, mach_task_self(), 0, &rotDomainConnect);
1935    if (KERN_SUCCESS != kr) {
1936        goto exit;
1937    }
1938
1939    ret = IOConnectCallMethod(rotDomainConnect, kPMSleepWakeWatchdogEnable,
1940                    NULL, 0,
1941                    NULL, 0, NULL,
1942                    NULL, NULL, NULL);
1943
1944    if (kIOReturnSuccess != ret)
1945    {
1946        goto exit;
1947    }
1948
1949exit:
1950    if (IO_OBJECT_NULL != rotDomainConnect)
1951        IOServiceClose(rotDomainConnect);
1952
1953}
1954
1955#endif
1956
1957static void initializeSleepWakeNotifications(void)
1958{
1959    IONotificationPortRef           notify;
1960    io_object_t                     anIterator;
1961
1962    _pm_ack_port = IORegisterForSystemPower(0, &notify,
1963                                    SleepWakeCallback, &anIterator);
1964
1965    if ( _pm_ack_port != MACH_PORT_NULL ) {
1966        if(notify) CFRunLoopAddSource(CFRunLoopGetCurrent(),
1967                            IONotificationPortGetRunLoopSource(notify),
1968                            kCFRunLoopDefaultMode);
1969    }
1970}
1971
1972