has NSProcessInfoActivity to disable app nap changed on high sierra?

A LONG time ago I added the MBS plugin code to disable appnap for an app that needs to be ready to receive commands in the background via creating an NSProcessInfoActivityMBS class and telling it that I was doing a user initiated activity. This has been working since OSX 10.9. now under high sierra I’m starting to have some users telling me that the app goes to sleep again. I’ve finally been able to duplicate the issue myself on my testing machines. The app stops responding to anything while the screen is asleep but wakes up as soon as the screen wakes up. The machine has not gone to sleep, just the screen is asleep.

Is there something new in Sierra or high sierra that doesn’t like long term user activities? Or that it simply doesn’t work anymore? Something is very different now than it used to be and I’m not sure what yet. I don’t see any documentation that says Apple is getting more strident about napping your apps when they are occluded or something.

What do you do with the activity?
I mean which flags?
You keep the object till your activity is done?

I have begun to notice this too with the application that I’m working on at the moment.

I thought “NSActivityUserInitiated” was meant to be the key to use. It looks like we could try combining it with this one also “NSActivityIdleDisplaySleepDisabled”.

The other way, which I have not verified at all is to use a helper application as terminal based applications do not adhere to App Nap, okay, let me clarify this, when I researched it two years ago, they supposedly didn’t.

The app itself starts up and creates an activity with both userInitiated and disable sleep flags set like:

Dim workingInfo As New NSProcessInfoMBS
Dim workingActivityInfo As Integer = Bitwise.BitOr( workingInfo.NSActivityIdleSystemSleepDisabled, workingInfo.NSActivityUserInitiated)

CurrentNSProcessActivity = workingInfo.beginActivity( workingActivityInfo, “automation is happening”)

If CurrentNSProcessActivity <> Nil Then
WriteLog( “app nap and system sleep are disabled”)
Else
WriteLog( “failed to disable app nap”, kAEULogRed)
End If

Where CurrentNSProcessActivity is a property of the Application class and it hangs around until close so I do keep the object in scope. As soon as you wake up the screen, or just randomly in the background sometimes, the app wakes up and tries to catch up, but it can be kept asleep for hours at a time even with this process logged. Maybe they think that since it’s a user process and there can’t be a user if the screen is asleep I should stop doing it? That would be bad… The app starts many command line helper apps in the background, and those keep running just fine, they can’t talk to their parent app anymore. I can ssh in and see that in top is never comes out of “sleeping” but I don’t know how to see the app nap flag like the activity monitor shows from the command line, is there a way to do that? As soon as I wake the screen up the app goes back to running normally, but with thousands of queued up messages to process from all it’s helper apps.

My thoughts are that perhaps a task has an upper limit on time? This didn’t start to happen normally for several hours after launch or more. I could close the task and create a new one periodically. I could register a background task as well as a user task in case it’s thinking we’re in the background now it might let that continue. Or I could also add the flag for needing low latency and realtime priority… But I don’t want to do that if I can help it. I will also experiment with keeping the screen awake with the NSActivityIdleDisplaySleepDisabled flag. It takes so long to duplicate the problem though that it’s hard to test all these combinations in any reasonable amount of time!

I’m adding in some code right now to see if it’s a thermal state change that is causing it to be app napped by the system. Something is definitely wrong or at least different with this in High Sierra as this as worked perfectly since they introduced it and I first added your example code to keep the app working.

I don’t also need to keep a reference to the NSProcessInfo class do I? Just the NSProcessActivity class right?

Well, for me it sounds fine.
Of course you can try to start a new activity every hour or so.

Just keep NSProcessInfoActivityMBS. You can keep the NSProcessInfoMBS around and reuse it.

I’ve added that to the test machine code already this morning, so it’s rolling over a new activity every few minutes. We shall see if it makes it through the night without hanging up.

10.13 is causing my external processes to sleep even with App Nap disabled and turning off lowpri_throttle_enabled in sysctl. I’ve bug reported this to Apple (though I expect no response or changes before 10.18). Some of my backend processes can run for days.

According to my understanding of Apple’s declaration are these two not the same?

NSActivityUserInitiated = (0x00FFFFFFULL | NSActivityIdleSystemSleepDisabled)

Well this confirms what I thought I understood about non-gui executable being excluded from App Nap.

IIRC, with Backup To Go, it’s not a regular GUI application (so that it sits in the menubar and not the dock) and for this I had to do extra work to enable App Nap.

I would assume that it might work as we’re basically saying this needs to continue, but doesn’t need to be a priority.

Please let us know.

That’s just sad.

My guess is that that they’ve probably decided that since the screen if off, GUI apps should be napping, without considering the consequences. Maybe set the display sleep to be a really small interval and test to confirm this.

Rolling over the user tasks did not make any difference. The thing that has so far stopped the problem was to disable turning off the screen in the energy saver control panel. I guess once the screen shuts off they think there is no user there to have initiated a task. I have added the no idle display sleep flag to the same activity creation and will see if that also does it.

It ran all last night with the screen powered off but on as far as the computer is concerned powered on and did not hiccup once. Of course I changed too many things at once so I don’t know if it’s the powering off the screen or the starting of the screen saver which I also disabled. Will now test with those combinations and see if it continues to run properly or hang up. This is not a conclusive test as it didn’t happen to me for several weeks after first updating this machine to High Sierra, so it might actually have been in one of the point releases since then. Or it might just be waiting for me to go to sleep tonight to do it, I’ll keep you all updated…

Lastly I’ll try adding that background task as well and see if that keeps it running even with the screen turning off. Right now I’ve just told my users to go into the energy savers preferences and don’t let it sleep the display. Not an ideal option but something that might keep us going while I continue to screw around with this.

Generally a background task is at a lower priority than a user task so I don’t want to be relegated to that even in the background but perhaps if I have both flags set it will do something. I’ll test with that next.

This is definitely a significant change in how app nap is handled from Apple and yet I can’t find anything in their docs about it at all. Did I miss the release note somewhere?

yes, that was my thought too since they all wake up as soon as the screen does so that is what I setup yesterday. It looks like this is the case.

Probably not. I’ve done a quick search in Apple’s API changes and couldn’t see anything related to NSProcessInfo.

Adding the bit for disabling idle screen sleep did not help. Only manually setting the screen to never go to sleep in the energy saver. Running now with both the user initiated flag as well as the background activity flag set and will see what happens this morning.

Have you guys tried adding a daemon for your GUI app to “run” it at certain intervals? In my experience, this still works in 10.13.x and appears to do what you need.

Do you have an example for testing?

I don’t quite follow what you mean. The app I’m testing with has a dozen different helper apps running inside of shell classes all the time. They are not affected by the app nap problem and happily continue to provide web services and other things, but cannot talk to or send any commands to the parent app when it’s been put to sleep. Is it the act of launching one that somehow stops this? Because just having one running does not stop it.

I’m running now with 2 “activities” registered. A regular user activity and a background activity. Perhaps I’ll be allowed to continue to operate with a background task registered if there is no user but it will be a few hours or more before I know if this makes any difference.

Adding a background activity does not work either. The app is still napped at some time after the screen is turned off.

I will try some other combinations, some talk that using the user activity allowing system sleep one works, but I’m not sure they are talking about the same issue.

I’m currently testing using a call to standard user defaults to write a boolean yes for the key “LSAppNapIsDisabled” rather than the previously valid “NSAppSleepDisabled” as it seems to have changed and so no longer works with the previous one. i’ll know in a few more hours if that works at all.

Doing a defaults write of boolean true to the key of LSAppNapIsDisabled does seem to stop it. The app was never put to sleep all night with that setting written at startup. That kind of defeats the purpose of having “tasks” that can start and end since it seems the only choice is to disable it completely for that app. Here’s what I did exactly at the beginning of my Open event:

Declare Function standardUserDefaults Lib "Foundation.framework" Selector "standardUserDefaults"(NSUserDefaultsClass As Ptr) As Ptr
Declare Function NSClassFromString Lib "Foundation.framework"(ClassName As CFStringRef) As Ptr
Declare Sub setBool Lib "Foundation.framework" Selector "setBool:forKey:"(NSUserDefaults As Ptr, Value As Byte, Key As CFStringRef)
Static standardUserDefaultsPtr As Ptr = standardUserDefaults(NSClassFromString("NSUserDefaults"))
setBool( standardUserDefaultsPtr, 1, "LSAppNapIsDisabled")

Apart from the change of the key to “LSAppNapIsDisabled” from the older “NSAppSleepDisabled” this code is the same as was posted in this forum by helpful folks back in the heady days of trying to get this working originally when Mavericks came out…

I will experiment now with some of the other keys you can pass to an NSProcessActivity but I don’t have high hopes for them. The only thing I haven’t tested is the one that is a user activity but allows idle sleep. I’ve always used the one that stops idle sleep but I did read one person on the intertubes suggesting that worked for them.

And sadly, I wish I could “un-answer” the above post because in spite of that High Sierra put my app into app nap even with that setting turned on. It took 19 hours of running in the background with the screen asleep before it did it, but it still did it.

There isn’t much else to try. In my previous testing turning off app nap globally to the machine seemed to work, but it takes so long to test I can’t be sure. Additionally setting the screen never to go to sleep also stopped it and has worked for some of my users too. None of the flags I am able to set from the app either via the user defaults or the NSProcess activity stuff has made any difference at all. There is one more combination I will try now but I know it’s not going to work. Sigh… This is extremely frustrating.

Even turning it off globally doesn’t sort it in High Sierra. These settings work for earlier versions:

defaults write NSGlobalDomain NSAppSleepDisabled -bool YES sudo echo debug.lowpri_throttle_enabled=0 >> /etc/sysctl.conf

But our backend threads sleep and then eventually zombie under 10.13. We’ve reported this via RADAR.