I've successfully followed the Daemons and Service Guide - Creating XPC Services tutorial, along with the SandboxedFetch
sample code and have a working Client / Service setup that is using the new NSXPCConnection
class.
What still isn't entirely clear to me is how to properly self-terminate the service application once it has finished its job. I recognize that in many cases, the service is expected to remain alive, but in the use-case I have in mind, the service will be used to only to do some processing that I'd otherwise not perform in the main application. Once that processing is finished, there's no reason for the service application to remain. If the client needs another service at a later date, it can just re-create a new one.
Since the service is a lightweight, non-nibbed, NSApplication
, I was trying to self-terminate it by calling invalidate
from inside applicationWillTerminate
, but that triggers an EXC_BAD_ACCESS exception almost every time. Calling invalidate
on the service's [NSXPCListener serviceListener]
generates slightly less reliable crashes, but it still crashes.
Calling invalidate
from within the client application on its NSXPCConnection
also generates an EXC_BAD_ACCESS exception almost every time.
So I'm curious what the correct sequence of steps is to cleanly shutdown the XPC service and then quit the service application. Ideally, the service would self-terminate after it has made its last XPC call to the client.
Attached is a small screenshot of what one of the exception's stacktrace looks like. (Yes, that's a webview that's loading in the service. Once the webview has finished loading, I want the service to self-terminate)
macOS uses XPC services for basic inter-process communication between various processes, such as between the XPC Service daemon and third-party application privileged helper tools.
The XPC Services API provides a lightweight mechanism for basic interprocess communication at the libSystem level. It allows you to create lightweight helper tools, called XPC services, that perform work on behalf of your app.
My first reaction is that you should not bother to terminate. When memory pressure occurs and your service is idle, launchd will kill your service. Exiting probably isn't in anyone's best interest because your service will take time to launch again. Don't terminate and you won't have to figure out why your attempt crashes.
But if for some reason you are determined to terminate, don't try so hard. Just do whatever you need to do to clean up (flush buffers, close network connections gracefully so the server doesn't suffer, whatever) and call exit. Although you seem to be using NSApplication, your service is not an application in any sense that the user cares about and there is no compelling reason to act like one in this respect. The host application needs to be able to cope with your service crashing anyway, so your deliberately exiting unceremoniously is just fine.
By the way, using NSApplication in an XPC service probably isn't the best idea because there's no supported way to declare that you want that. This might help explain why it isn't working as well as you'd like, though this paragraph should not be construed as a proper analysis of the crash. :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With