On a macOS machine running v15.0, I have a daemon run by launchd which subscribes to the sleep and wakeup notifications using the IORegisterForSystemPower
method.
void PowerCallBack(void* refCon, io_service_t service, natural_t messageType, void* messageArgument)
{
switch (messageType)
{
case kIOMessageSystemWillSleep:
logger->Debug("Received sleep notification from macOS");
if (refCon)
{
//Handle Sleep
}
IOAllowPowerChange(root_port, (long)messageArgument);
break;
case kIOMessageSystemHasPoweredOn:
logger->Debug("Received wakeup notification from macOS");
if (refCon)
{
// Handle Wakeup
}
break;
default:
break;
}
}
void MacOSNotification::RegisterNotifications()
{
logger->Debug("Registering for notifications from macOS");
powerNotificationThread = [[NSThread alloc] initWithBlock:^{
// Notifier object, used to deregister later
root_port = IORegisterForSystemPower(this, ¬ifyPortRef, PowerCallBack, ¬ifierObject);
if (root_port == 0)
{
return;
}
logger->Debug("Registered for system power notifications from macOS");
// Add the notification port to the application runloop
CFRunLoopAddSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(notifyPortRef),
kCFRunLoopCommonModes);
CFRunLoopRun();
}]; //END OF THREAD BLOCK
[powerNotificationThread start];
}
Using this mechanism, I am getting notifications for normal sleep and wakeup transitions like closing and opening the lid. I need these notifications to terminate/reconnect my connection to a cloud service when we go to sleep/wakeup respectively.
I have noticed from the power logs at /private/var/log/powermanagement
that the after the sleep initiated by lid closing or clicking sleep in the top apple menu (both of which I can detect as they generate power notification), the macOS machine wakes up with the following message from powerd logs:
DarkWake from Deep Idle [CDNP] : due to SMC.OutboxNotEmpty smc.70070000 wifibt/
I do not get any notification for this wakeup and my application threads start running. This happens every 15 to 16 mins from my observation.
After this DarkWake, we go back to 'Maintenance' sleep in under a minute as can be seen by the following powerd log:
Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active
I do not get any notifications for this either.
Is there a way to track and get notified of these DarkWake -> Maintenance sleep cycles? At the very least I would like to log when we go into and come out of these states. Currently I just rely on seeing a 15 min window of no logs to know this must have a DarkWake -> Maintenance sleep cycle.
Also is there a way to make sure my application and its threads are not woken up by DarkWake (like an opt-out)? I would like to make it so that my application only runs when we are properly sleeping and waking.