Concurrent XPC connections to an extension process and its scenes?

When using ExtensionKit, is it expected that an app would be able to open concurrent XPC connections to both an extension process (via AppExtensionProcess.makeXPCConnection) and that extension's scenes (via EXHostViewController.makeXPCConnection)?

I'm finding that if I make a connection to an extension process, communication with the process works fine until I try to make a connection to a scene in that extension ... at which point the extension receives SIGKILL and an OSLaunchdErrorDomain code 137 "Service does not support the specified action" error is logged to the console.

Similarly, if I first make one or more connections to extension scenes, communication with the scenes works fine until I try to make a connection to the extension process ... at which point the same result and error occur.

So it seems that I can either communicate with an extension process or that extension's scenes, but not both. Is this an expected limitation, or should I be able to communicate with an extension process and its scenes at the same time?

Hi,

... should I be able to communicate with an extension process and its scenes at the same time?

I don't think so, at least not within the construction of ExtensionKit. I' haven't traced through it's full implementation but, as far as I can tell, each extension point eventually ends up having a single XCP endpoint which is derived from the extension metadata itself. That's why you don't have to explicitly say what XPC connection you're connecting to- it's implicit in the ExtensionKit configuration data.

That's what leads to this kind of behavior:

Similarly, if I first make one or more connections to extension scenes, communication with the scenes works fine until I try to make a connection to the extension process ... at which point the same result and error occur.

I think what's going on here is that which ever connection type you choose first (AppExtensionProcess vs EXHostViewController) ends up initializing the XPC endpoint. The second connection then fails because it tries to connect to the endpoint you just created and is then rejected because it doesn't "match" the connection type.

-Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi,

So, one thing I'd like to understand better is why/what you actually "need" this for. The reason for the "basic" limitation here isn't all that complicated- ExtensionKit was designed around a "one endpoint" model, so that's just the way it happens to work. That main advantage of this approach is that it simplifies the entire API design, as it allows you to think of an extension as "a component I communicate with that provides a specific interface", NOT "a component I find and then choose a particular interface on".

I think the other reason they choose this approach is that they didn't really consider it much of a limitation/restriction.

Going back to your original explanation here:

...open concurrent XPC connections to both an extension process (via AppExtensionProcess.makeXPCConnection) that extension's scenes (via EXHostViewController.makeXPCConnection)?...

The typical way you would implement something like this is not to open two independant XPC connections, it to open the "primary" XPC connection (in the context of ExtensionKit, this would "the extension") and THEN have that XPC connection vend another XPC connection "to" the client. The context is slightly different, but this is the same technique that's described in the "XPC Rendezvous" section of "XPC and App-to-App Communication".

Also, as a side comment here, it's important to keep in mind how the "larger" context of this kind of API plays out in an app. For example, imagine you had an extension architected like this;

a) The extension provides a user interface that's used to configure "something".

b) The extension the provides an XPC connection that's used to complete the work configured in "a".

The tricky point here is that in most cases connection "b" should actually be to some other component your broader architecture, NOT directly the the extension. Turning that into a more concrete example, think about the two different "extremes" of the "work" involved in "b":

  1. The actual work involved requires minimal time (say 0.1s).

In that case, why bother creating a whole separate interface, etc? Just include whatever you need in the XPC interface for "a", finish everything "at once", and then "everything" can be destroyed when your extension exits.

  1. The actual work involved will require substantial time (say 60min).

Now the problem isn't just with keeping an extension active for 60min, it's with assuming ANYTHING (extension/app/the entire system) will continue to be running uninterrupted for the next 60min. For most case, the right approach here is for your extension to vend an interface to a different component (typically a daemon), which is then responsible for managing the entire work lifetime.

I'm not sure where you your needs fit along that spectrum, but I hope that opens up some new ideas about how you can approach this.


-Kevin Elliott
DTS Engineer, CoreOS/Hardware

The basic architecture is that the host application defines an extension point that extensions can conform to in order to provide a service to the host application. The service does not inherently have UI associated with it, so the idea is to transact that service via an XPC connection to the extension process.

Depending on the extension, the service may be configurable in some way by the user. The UI that would be used to configure the service is provided by the extension and is hosted in an EXHostViewController. The idea is to exchange configuration information via an XPC connection to individual scenes containing any configuration UI.

If only one type of XPC connection can be made to an extension, then there appears to be two choices:

  1. All communication between the host and the extension must be conducted via the single XPC connection to the extension process. The extension would need to export an interface that allows the service to be transacted, and also allows the host to identify a scene to exchange configuration information with.
  2. The service itself is transacted via a special "scene" that is associated with a EXHostViewController solely for the purpose of creating an XPC connection using EXHostViewController.makeXPCConnection(), but that scene's UI would never actually be visible.

In my case, I estimate that #2 would be preferred over #1. The extension does not provide a short-running service, it is expected to be active during the entire life of the host process and will terminate when the host terminates.

I could get more specific with the architecture, but would prefer to do so via the FBA or a code-level support request.

Concurrent XPC connections to an extension process and its scenes?
 
 
Q