Xpc service, how to avoid restarting

I created a Xpc daemon service using C++ (not NSXConnect api), my client application doesn't have problem in talking to it. I want to keep some data
in the service, but the XPC service daemon sometime restart itself unpredictably, this will cause all the data inside it lost.
I checked the code, nothing caused the restart.
Looks like once client call xpc_connection_resume(service),
the daemon will restart.
My ideal way is that, after system boot/user login, this XPC service will not restart until system restart, is it possible?
  • S

Replies

Is this a launchd daemon or agent that vends an XPC service using the MachServices property in its launchd property list (see the launchd.plist man page)? Or an XPC Service proper (see the xpcservice.plist man page)?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
It is a launchd daemon, something like this, handler ignored since client apps can talk to it:

Code Block
int main(int argc, const char *argv[])
{
syslog(logLevel, "😎 L%d: start XpcEndPoint", __LINE__);
const char *name = "com.me.driver.myaudio.xpc.XpcEndpoint";
/*dispatch_queue_t queue = dispatch_queue_create("TestXPC", 0);*/
xpc_connection_t service = xpc_connection_create_mach_service(name, DISPATCH_TARGET_QUEUE_DEFAULT, XPC_CONNECTION_MACH_SERVICE_LISTENER);
if (!service)
{
syslog(logLevel, "😎 failed to create service");
return;
}
/*xpc_connection_activate(service);
xpc_connection_set_context(service, this);
auto pSrv = this;*/
xpc_connection_set_event_handler(service, ^(xpc_object_t connection) {
xpc_connection_set_context((xpc_connection_t)connection, pSrv);
XpcServer::new_connection_handler((xpc_connection_t)connection);
});
xpc_connection_resume(service);
dispatch_main();
xpc_release(service);
}


=====the launchdaemon plist =========
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ...>
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.me.driver.myaudio.xpc.XpcEndpoint</string>
<key>MachServices</key>
<dict>
<key>com.me.driver.myaudio.xpc.XpcEndpoint</key>
<true/>
</dict>
<key>ProgramArguments</key>
<array>
<string>/Library/Audio/Plug-Ins/HAL/MyAudio.driver/Contents/XPCServices/XpcEndpoint.xpc/Contents/MacOS/XpcEndpoint</string>
</array>
<key>ProcessType</key>
<string>Adaptive</string>
<key>KeepAlive</key>
<true/>

</dict>
</plist>

====Add in the log===== // The bold lines were restart
2021-03-21 18:43:43.277902-0600 0x75d Default 0x0 278 0 com.apple.audio.Core-Audio-Driver-Service: (MyAudio) 😎 PrepareXPCServer ===>
2021-03-21 18:43:43.277997-0600 0x75d Default 0x0 278 0 com.apple.audio.Core-Audio-Driver-Service: (MyAudio) 😎 L210: sending XPC message: <dictionary: 0x7feb1ee041f0> { count = 3, transaction: 0, voucher = 0x0, contents =
2021-03-21 18:44:53.343469-0600 0x1822 Default 0x0 607 0 com.apple.audio.Core-Audio-Driver-Service: (MyAudio) 😎 L210: sending XPC message: <dictionary: 0x7fb308609080> { count = 3, transaction: 0, voucher = 0x0, contents =
2021-03-21 18:44:54.924630-0600 0x343 Default 0x0 80 0 XpcAgent: 😎 L14: start XpcEndPoint :
2021-03-21 18:44:54.924649-0600 0x343 Default 0x0 80 0 XpcAgent: 😎 XpcServer constructor 0x7fef83f04080
2021-03-21 18:44:54.924664-0600 0x343 Default 0x0 80 0 XpcAgent: 😎 XpcServer::Run
2021-03-21 18:44:54.925038-0600 0x1840 Default 0x0 80 0 XpcAgent: 😎 L66: Client Msg: <dictionary: 0x7fef83f04c00> { count = 3, transaction: 1, voucher = 0x7fef83f04350, contents =
2021-03-21 18:44:54.925042-0600 0x1842 Default 0x0 80 0 XpcAgent: 😎 L66: Client Msg: <dictionary: 0x7fef83e04100> { count = 3, transaction: 1, voucher = 0x7fef83e04230, contents =
2021-03-21 18:44:54.925086-0600 0x1840 Default 0x0 80 0 XpcAgent: 😎 L119 dealWithRegistration: size of table = 1
2021-03-21 18:44:54.925108-0600 0x1840 Default 0x0 80 0 XpcAgent: 😎 L137 reply client: <dictionary: 0x7fef83e04a30> { count = 3, transaction: 1, voucher = 0x7fef83f04350, contents =
2021-03-21 18:44:54.925150-0600 0x1822 Default 0x0 607 0 com.apple.audio.Core-Audio-Driver-Service: (MyAudio) 😎 L215: XPC replied: <dictionary: 0x7fb308609930> { count = 3, transaction: 0, voucher = 0x0, contents =
2021-03-21 18:44:54.925155-0600 0x1822 Default 0x0 607 0 com.apple.audio.Core-Audio-Driver-Service: (MyAudio) 😎 Registrated XPC service successfully!
2021-03-21 18:44:54.967501-0600 0x1861 Default 0x0 609 0 XpcAgent: 😎 L14: start XpcEndPoint :
2021-03-21 18:44:54.967511-0600 0x1861 Default 0x0 609 0 XpcAgent: 😎 XpcServer constructor 0x7fc56a5045a0
2021-03-21 18:44:54.967515-0600 0x1861 Default 0x0 609 0 XpcAgent: 😎 XpcServer::Run
2021-03-21 18:44:54.968272-0600 0x187a Default 0x0 609 0 XpcAgent: 😎 L66: Client Msg: <dictionary: 0x7fc56a704980> { count = 3, transaction: 1, voucher = 0x7fc56a704470, contents =
2021-03-21 18:44:54.968311-0600 0x187a Default 0x0 609 0 XpcAgent: 😎 L119 dealWithRegistration: size of table = 1
2021-03-21 18:44:54.968335-0600 0x187a Default 0x0 609 0 XpcAgent: 😎 L137 reply client: <dictionary: 0x7fc56b8043a0> { count = 3, transaction: 1, voucher = 0x7fc56a704470, contents =
2021-03-21 18:44:54.968908-0600 0x1855 Default 0x0 610 0 com.apple.audio.Core-Audio-Driver-Service: (MyAudio) 😎 L215: XPC replied: <dictionary: 0x7fe3d6804670> { count = 3, transaction: 0, voucher = 0x0, contents =
2021-03-21 18:44:54.968913-0600 0x1855 Default 0x0 610 0 com.apple.audio.Core-Audio-Driver-Service: (MyAudio) 😎 Registrated XPC service successfully!
2021-03-21 18:44:54.968931-0600 0x1855 Default 0x0 610 0 com.apple.audio.Core-Audio-Driver-Service: (MyAudio) 😎 Done with PrepareXPCServer, moved on!
2021-03-21 18:45:04.981495-0600 0x1dcd Default 0x0 680 0 XpcAgent: 😎 L14: start XpcEndPoint :
2021-03-21 18:45:04.981511-0600 0x1dcd Default 0x0 680 0 XpcAgent: 😎 XpcServer constructor 0x7fb23f504380
2021-03-21 18:45:04.981516-0600 0x1dcd Default 0x0 680 0 XpcAgent: 😎 XpcServer::Run


It is a launchd daemon

OK. And what does your launchd property list file look like?

handler ignored since client apps can talk to it

I don’t understand what you mean by this. Please clarify.

Share and Enjoy

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

This is the launchd plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ...>
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.me.driver.myaudio.xpc.XpcEndpoint</string>
<key>MachServices</key>
<dict>
<key>com.me.driver.myaudio.xpc.XpcEndpoint</key>
<true/>
</dict>
<key>ProgramArguments</key>
<array>
<string>/Library/Audio/Plug-Ins/HAL/MyAudio.driver/Contents/XPCServices/XpcEndpoint.xpc/Contents/MacOS/XpcEndpoint</string>
</array>
<key>ProcessType</key>
<string>Adaptive</string>
<key>KeepAlive</key>
<true/>

</dict>
</plist>

>>>I don’t understand what you mean by this. Please clarify.

That means I didn't post the event handler callback so that we can focus on the restart issue, the callback is working as expected, other clients can connect to it, send XPC message and get response.

Again, my problem is the XpcService restarts unpredictably, once it restarts, the data kept in the XpcService(basically the hash route table for delivering msg from one client to other subscribed client) will lost, if the Xpc service could start with launchd, keep live until system restart/shutdown, it will be ideal.
I can see VTEncoderXPCService/VTDecoderXPCService in activity monitor, I guess those Video Tool Box services might have the same requirements.



This is the launchd plist

OK, you’re doing something very weird here. You seem to have created an XPC Service (XpcEndpoint.xpc) but are then trying to run it as a launchd daemon. It’s possible that’s crossing the streams in a way that causes your daemon to opt in to the XPC Service lifecycle.

For the moment I recommend that you undo this packaging, and just make your daemon a standalone executable. In that case, and assuming you have KeepAlive set, the launchd lifecycle should keep your daemon running indefinitely.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Thanks to eskimo, I'll need redo it since deleted my stuff accidentally two weeks ago and just got chance get back to this thing.
Got time to dig into the problem, it turns out the restarting of XPC service was caused by xpc_release the connection which leads to the XPC service crash, any safe way to release a connection? tried try/catch and it didn't work.

any safe way to release a connection?

You shouldn’t need to do anything special to release an XPC connection. I generally recommend that you enable Objective-C ARC (or use Swift) in which case the XPC connection become a reference counted object that’s automatically managed like any other Objective-C object.

Share and Enjoy

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