SMAppService

Hello,

https://developer.apple.com/forums/thread/802443 https://developer.apple.com/documentation/servicemanagement/updating-helper-executables-from-earlier-versions-of-macos https://developer.apple.com/documentation/ServiceManagement/updating-your-app-package-installer-to-use-the-new-service-management-api#Run-the-sample-launch-agent

Read these. Earlier we had a setup with SMJobBless, now we have migrated to SMAppService.

Everything is working fine, the new API seems easier to manage, but we are having issues with updating the daemon.

I was wondering, what is the right process for updating a daemon from app side?

What we are doing so far: App asks daemon for version If version is lower than expected: daemon.unregister(), wait a second and daemon.register() again.

The why? We have noticed that unregistering/registering multiple times, of same daemon, can cause the daemon to stop working as expected. The daemon toggle in Mac Settings -> Login Items & Extensions can be on or off, but the app can still pickup daemon running, but no daemon running in Activity monitor. Registration/unregistration can start failing and nothing helps to resolve this, only reseting with sfltool resetbtm and a restart seems to does the job. This is usually noticeable for test users, testing same daemon version with different app builds.

In production app, we also increase the bundle version of daemon in plist, in test apps we - don't.

I haven't found any sources of how the update of pre-bundled app daemon should work. Initial idea is register/unregister, but from what I have observed, this seems to mess up after multiple registrations. I have a theory, that sending the daemon a command to kill itself after app update, would load the latest daemon. Also, I haven't observed for daemon, with different build versions to update automatically.

What is the right way to update a daemon with SMAppService setup?

Thank you in advance.

Is your daemon embedded in your app? That is, are you using BundleProgram?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hey, sorry for not the greatest title, initially thought I will be able to edit and polish title and content, but saw in the forums, that it is possible to do that only for a short amount of time.

Getting back to the topic:

https://github.com/nymtech/nym-vpn-client/blob/develop/nym-vpn-apple/Daemon/net.nymtech.vpn.helper.plist

Yes, we are using BundleProgram.

Thanks for confirming that.

If you’re using BundleProgram then there’s only one copy of your daemon on the system at any given time, the one embedded within your app. Which brings us to this:

I have a theory, that sending the daemon a command to kill itself after app update, would load the latest daemon.

That’s what I’d expect. Please give it a whirl and let us know how you get along.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hello again, it seems like macOS memory protection kicks in and does not allow starting/restarting different executable.

Further, I have noticed that app built with xCode 16.4 allows daemon updates via SMAppService with unregister/register.

App built with xCode 26.0.1 does not succeed in the same approach.

After a while, toggling the System Preferences -> General -> Login items & extensions, it is possible to get the updated daemon running, but it's inconsistent.

Here's what I tried:

  • automatic update with SMAppService register/unregister after app update
  • toggle the daemon toggle in System Preferences after app update off/on.
  • manually call unregister command from app, wait a bit register.

All of these end up in daemon not starting the first time as in console log provided.

What is the correct way, to update the daemon with SMAppService?

it seems like macOS memory protection kicks in and does not allow starting/restarting different executable.

Hmmm, I’m not sure how memory protection is a factor here.

The log snippet you posted suggests that your daemon is crashing. Does that generate a crash report? If so, please post it here. See Posting a Crash Report for advice on how to do that.

Also, how are you updating your app? Make sure that you’re not hitting the problem described in Updating Mac Software. Specifically, use the instructions in Check Third-Party Software Updaters to verify that your new daemon was written to a new file with a new inode number.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

SMAppService
 
 
Q