Hi,
I'm developing an macOS app which includes an agent (registered as login item) which is intended to run for entire duration of user's login session.
The agent's bundle also includes few application extensions. The application is intended to be distributed outside of App Store. It is not going to be sandboxed but rather notarized, so I'm using hardened runtime.
I want to add some application extensions (for example: a file provider etension) to be bundled with the agent.
The extensions are sandboxed and belong to the same application group as main application and the agent.
Extensions should do some IPC calls on the running agent process.
I think the most convenient solution for the IPC would be to use the XPC service, so, in the agent, I'am creating an XPC listener registered to mach service name.
Now I want to connect to the XPC service provided by the agent from the app extensions. This, however, fails with the following error:
Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named abcd.service was invalidated: failed at lookup with error 159 - Sandbox restriction."
My application bundle has now the following structure:
MainApp.app --- main application bundle (hardened runtime)
Contents/Library/LoginItems/agent.app --- agent with XPC service (hardened runtime)
.../agent.app/Contents/PlugIns/AppExt1.appex --- app extension 1 (sandboxed)
.../agent.app/Contents/Plugins/AppExt2.appex --- app extension 2 (sandboxed)
Searching through the forum I've found another post, which advises to bundle the XPC service within the app extension to mitigate this issue. This, however, does not seem like a viable solution for my problem: what I need is to call the code on the running agent instance.
As an alternative I considered to create a unix domain socket in the application group container and use that for communication between the agent and its extensions. XPC however is more convenient so if there is any way to make it working for the above scenario, I would be interested to learn about it.
The agent creates XPC listeners with mach service names:
S1J6DZ9E7U.com.myapp.agent.srv1
andS1J6DZ9E7U.com.myapp.agent.srv2
.
This won’t work. A Service Management login item can only run a single XPC listener and its name must match the name of the login item. For (a very old and very crufty)-: example of how to set this up, see AppSandboxLoginItemXPCDemo.
When debugging, I run the agent direcly from Xcode instead of relying upon it to be started by launch services.
That’s fine for day-to-day debugging but it’s a bad idea during this bring up phase. Xcode has special magic to help you debug XPC Services and that magic allows you to do things that you won’t otherwise work, for example, register a XPC listener with an unexpected name.
My general advice on this front:
-
Use the technique in TN3113 Testing and debugging XPC code with an anonymous listener to bring up your core XPC functionality within a single process.
-
Once you have that working, move the listener to your Service Management login item and test it from a non-sandboxed client, like your app. Make sure to start the login item by calling
SMLoginItemSetEnabled
, not be running it from Xcode. -
Then try to get things working in a sandboxed client.
The last step may require you to apply the com.apple.security.temporary-exception.mach-lookup.global-name
temporary exception entitlement but I don’t think it’ll necessary because of the App Group Mach service name exception discussed here and here.
And yes, this is a very tangled web we’re weaving here (-:
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"