Return of the zombie app: is it a feature or bug?

Yesterday’s article about apps going into a zombie state brought generous help from Jeff @lapcatsoftware, and some clarification, even if the mystery deepens more generally. This behaviour is not confined to Apple’s apps, although it seems most common in them, and it all depends on a flag in the app’s Info.plist file.

Some apps – TextEdit and Preview are good and long-standing examples – automatically quit if you put them into the background without any document or window open, a behaviour which I am sure you have noticed. There was a time when they only quit if they had not been launched explicitly by the user, so you could open the app (rather than opening a document which opened that app) and leave that open if you wished, but that workaround to their self-quitting stopped working some time ago.

Setting this behaviour

The way that this normally works is by the app developer setting a flag in the app’s Info.plist property list, NSSupportsAutomaticTermination, to <true/> This operates completely independently of whether that app can nap: the developer can prevent App Nap by setting a different flag in Info.plist, NSAppSleepDisabled, to <true/>

What I think used to happen was that, when automatic termination was triggered by the app going into the background without an open document, the app promptly quit, just as it does when the user operates the Quit command in the app’s menu. In Sierra and High Sierra (at least) that is not the case, and zombie apps can hang around for hours.

So any app with its NSSupportsAutomaticTermination flag set to true will now sit around as an active process after its icon has been removed from the Dock or, if it’s installed in the Dock, the black dot below the icon has been removed to indicate that the app has closed. As the app is a zombie and cannot be used normally any more, if it can enter App Nap, it will do so. If it cannot, it will remain in the list of running processes in Activity Monitor. It will also remain accessible in the Force Quit dialog, but not in the App Switcher, Dock, etc.

It’s a feature

For once, Apple’s documentation in its Information Property List Key Reference is very informative, and casts new light on exactly what is going on:

NSSupportsAutomaticTermination (Boolean – macOS). This key contains a Boolean value that indicates whether the app supports automatic termination in OS X v10.7 and later. Automatic termination allows an app that is running to be terminated automatically by the system when certain conditions apply. Primarily, the app can be terminated when it is hidden or does not have any visible windows and is not currently being used. The system may terminate such an app in order to reclaim the memory used by the app.

This can also be controlled in code, without any setting being visible in the Info.plist, although thankfully that appears to be uncommon practice.

So what is happening in these apps is that they are handing over their control to macOS. If and when macOS wishes to, for example when it needs more free memory, it will terminate the app. However, macOS also removes the app from those indicators which users rely on to tell them whether an app is running, and to let them switch to using that app. There are only two easy ways of using a zombie app again: one is to open a document which would normally open that app, and the other is to try to open the same copy of the app which is currently a zombie.

macOS does not let the user have access to the zombie app through the most common tools for accessing apps, particularly the Dock, which pretend that the app has quit, when it probably hasn’t.

Impact

For ‘small’ utilities such as Preview and TextEdit, which we often only open by double-clicking on a document which they normally handle, this doesn’t seem particularly abusive behaviour.

For more substantial working apps like Pages and Numbers, and even more so with Apple’s Xcode, I think it is utterly perverse. Unless you already have that app installed in the Dock (or your other app launcher), reviving a zombie app is far more effort than waking one which is merely in App Nap. Indeed, it is no different from starting the app from scratch. The only user benefit then is the reduction in time for the app to ‘load’, as a zombie is already loaded and ready, when you can find it.

It is also deceptive to the user, who has long been tricked into believing that the apps which are running are those marked as running in the Dock, or in the App Switcher.

It tripped me up yesterday when I was working on this article. Users cannot modify the Info.plist file in an app, as doing so will break the app’s signature, normally causing an error or crash when you try to open the app (instead of a specific complaint that signature is broken). So at Jeff’s suggestion, I built a copy of Woodpile with the NSSupportsAutomaticTermination flag set, and watched it turn into a zombie.

I then hastily removed that flag from my source code, so that my app wouldn’t use this aberrant behaviour. However, the copy of Woodpile which should have quit, as it was still running as a zombie, couldn’t be trashed or replaced by a freshly-compiled version, as macOS considered that it was still in use, and wouldn’t terminate it. As I have several different versions of Woodpile here, I then had to locate the copy which was running as a zombie, ‘open’ it so that I could quit it properly, and finally get rid of it.

appnap06

There’s no solution

I have mentioned that, as users cannot change the Info.plist in apps, there is nothing that you can do to change any of this behaviour. This is made even more impossible in many of Apple’s apps, as those installed with macOS are now also protected by SIP. Neither is there any way to control this in an app’s preferences, unless it specifically supports that feature; I can’t see any that do.

I presume that the Human Interface Team at Apple were on a long vacation when this change to macOS was implemented, all those years ago, and as they too can’t see these zombie apps, they’re still none the wiser.

To recap and update my listing of app states, there are now four basic states for any app in macOS:

  • Running and not napping,
  • Running, in App Nap, and still fully accessible,
  • Running, but hidden from normal user access (possibly napping too) – a zombie,
  • Not running at all.

In case you’re hoping that Apple is doing something to change this situation, in this respect High Sierra 10.13.1 behaves exactly the same as Sierra, and more and more of Apple’s own apps now support it. As you might have expected, Apple doesn’t seem to have mentioned any of this in its documentation for users.