XPC is the preferred inter-process communication (IPC) mechanism on Apple platforms. XPC has three APIs:
The high-level NSXPCConnection API, for Objective-C and Swift
The low-level Swift API, introduced with macOS 14
The low-level C API, which, while callable from all languages, works best with C-based languages
General:
DevForums tag: XPC
Creating XPC services documentation
NSXPCConnection class documentation
Low-level API documentation
XPC has extensive man pages — For the low-level API, start with the xpc man page; this is the original source for the XPC C API documentation and still contains titbits that you can’t find elsewhere. Also read the xpcservice.plist man page, which documents the property list format used by XPC services.
Daemons and Services Programming Guide archived documentation
WWDC 2012 Session 241 Cocoa Interprocess Communication with XPC — This is no longer available from the Apple Developer website )-:
Technote 2083 Daemons and Agents — It hasn’t been updated in… well… decades, but it’s still remarkably relevant.
TN3113 Testing and Debugging XPC Code With an Anonymous Listener
XPC and App-to-App Communication DevForums post
Validating Signature Of XPC Process DevForums post
Related tags include:
Inter-process communication, for other IPC mechanisms
Service Management, for installing and uninstalling Service Management login items, launchd agents, and launchd daemons
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
XPC
RSS for tagXPC is a a low-level (libSystem) interprocess communication mechanism that is based on serialized property lists.
Posts under XPC tag
54 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
I'm trying to use XPC communicate between a command line tool (launched from Terminal) and a macOS application. My code currently works when the app is launched from Xcode, but not if I launch the built app from the command line (open path-to-foo.app) or if I try and distribute the packaged application (via "Development" distribution). Notably, the XPC works if the command line tool is launched from the terminal as long as the app itself is launched from Xcode.
I publish the XPC service using NSXPCListener(machServiceName: <team-identifier>.com.example.my-app.service) and connect to it using NSXPCConnection(machServiceName: machServiceName). Both my command line tool and my main app identical "app group" entitlements for $(TeamIdentifierPrefix)com.example.my-app and I verified the team identifier substitution was correct in both the app and command line tool after doing distributing for "App Store", exporting, unpacking the pkg and running codesign as described here: https://developer.apple.com/documentation/xcode/embedding-a-helper-tool-in-a-sandboxed-app
We've got a non-sandboxed app with a built-in daemon that does some root-privileged things for us on occasion. We're using the newest SMAppService APIs, using NSXPCConnections for communications, and generally things work as expected. The daemon is set up to terminate when the parent app terminates.
Our app also has (and uses the daemon for) a self-update feature. Once the new app is downloaded, the daemon takes over, replaces the app in-place, terminates the old app and launches the new one.
However, after this update, the daemon no longer works.
Any other build & launch of the app will silently fail when trying to talk to the daemon. The XPC connection can be constructed as usual, no errors, the process goes along like it should app-side, but the daemon never actually launches and never responds.
I can imagine there could be a few rules being broken here with the self-update and the built-in daemon, but what would they be and how can we work within the rules?
We have a product which uses a Network Extension (a socket filter and a packet content filter). The application contains the network extension, as well as an un-sandboxed LaunchDaemon which connects to the service at the NEMachServiceName.
Occasionally, usually after an upgrade where the system extension is swapped for the new version, our un-sandboxed process isn't able to contact the network extension. From the logging, we receive the following XPC error
(libxpc.dylib) [com.apple.xpc:connection] [0x7fd6d0307f40] failed to do a bootstrap look-up: xpc_error=[3: No such process]
in the unsandboxed process. Eventually, we receive an invalidated callback on the XPC connection with the error Couldn’t communicate with a helper application.. We have confirmed that an appropriate service is running via the launchctl command, and the network extension process appears to have initialised correctly. We don't see any indication of a received connection at the Network Extension process however (probably not surprising given the error).
Once a system enters this state, repeated attempts to connect are unsuccessful and continue to produce the same error.
We've also confirmed that there are no XPC codec exceptions apparent that might cause the connection to fail.
I'm at a bit of a loss to explain why this failure might be occurring, other than a problem in the bootstrap/launchd being able to find the appropriate service. Is there possibly some problem with unsandboxed processes accessing the sandboxed network extension via XPC? They are both provisioned in an app group together. Is there possibly some issue where attempting to connect at a critical point during network extension installation causes it to become inaccessible?
We've observed this specifically on macOS 14.5 (23F79), however this is something we've noticed on other versions of macOS and our code. The problem isn't systematic, and systems end up in this state only occasionally. We do seem to find some customers have more instances of this problems than others, but we haven't been successful at teasing out any common thread that might explain why.
Let's image that someone wants to use a background service to keep track of FSEvents activity, at the file level (a firehose, some might say).
I choose this example, to indicate the volume and rate of data transmission in question. I'm not creating a front-end for FSEvents data, but my background service may generate data at a similar pace. The service runs off of user defined document/s that specify the FSEvent background filtering to be applied. Those that match get stored into a database. But filters can match on almost all the data being emitted by FSEvents.
The user decides to check on the service's activity and database writes by launching a GUI that sends requests to the background service using XPC. So the GUI can request historic data from a database, but also get a real-time view of what FS events the service is busy filtering.
So it's a client-server approach, that's concerned with monitoring an event stream over XPC. I understand XPC is a request/response mechanism, and I might look into using a reverse connection here, but my main concern is one of performance. Is XPC capable of coping with such a high volume of data transmision? Could it cope with 1000s of rows of table data updates per second sent to a GUI frontend?
I know there are streaming protocol options that involve a TCP connection, but I really want to stay away from opening sockets.
Hello,
I use setCodeSigningRequirement: in sandboxed XPCService and it seems that no matter what I always get errSecCSNoSuchCode[1] when the app is signed with development certificate. The same application signed with DeveloperID is fine.
I use following CSR for development signed builds.
identifier com.example.app and anchor apple generic
and certificate 1[field.1.2.840.113635.100.6.2.1] exists
and certificate leaf[field.1.2.840.113635.100.6.1.12] exists
But also tried to simplify to identifier com.example.app or just true.
If I validated the CSR with codesign -R I get "explicit requirement satisfied".
I spotted this log line:
Sandbox: com.example.app(67058) deny(1) file-read-data /Users/(...)/example-app/build/arm64-mac/src/mac/app/Debug/Example App.app/Contents/MacOS/ExampleApp
So I disabled the sandbox for XPCService and now everything works. But then why the DeveloperID signed build works with XPCService sandboxed? ...or does it really? :)
Just for completeness the CSR which I use in production build are:
identifier com.example.app and anchor apple generic
and certificate 1[field.1.2.840.113635.100.6.2.6] exists
and certificate leaf[field.1.2.840.113635.100.6.1.13] exists
and certificate leaf[subject.OU] = EXAMPLE
Hello,
The man page for xpcservices.plist states that:
Services embedded in an application bundle will only be visible to the containing application (...)
What exactly "visible" means? Doest that mean that there is a mechanism to prevent other programs than the embedding application to access the XPCService's mach port or it just means that the XPCService is not listed (e.g. launchctl list) and if attacker can guess the mach port they can access it?
I'm asking to understand if there is a security gain using the -[NSXPCConnection setCodeSigningRequirement:] for embedded XPCServices.
hi all.
I subscribe the notify write event, every time I recieve a notify write event message i will send log data and reply block(didn't do nothing) with async method to host app(Objc XPC API).host app will reply immediately once it recieves data. after a while my sysext crashed, then I checked system log find the log below.
launchd: exited with exit reason (namespace: 30 code: 0xc40000000004aaaa) - (unknown reason)
is it because of exceeding the maximum limit of xpc's block queue length, or too many memory allocation, or...
by the way, host app didn't crash.
how this happened exactly? how could i solve it?
How do you send an NSURL representing a new file, as returned from an NSSavePanel, to an XPC service such that the service is granted permission to create the file?
I can successfully pass an NSURL to the XPC process if the NSURL represents an existing file. This is documented in Apple's Documentation:
Share file access between processes with URL bookmarks
This involves creating bookmark date while passing 0 in as the options. However, if you try to create bookmark data for an NSURL that represents a file that is not yet created, you do not get any bookmark data back and an error is returned instead:
Error Domain=NSCocoaErrorDomain Code=260
"The file couldn’t be opened because it doesn’t exist."
Simply passing the file path to the XPC process, by way of:
xpc_dictionary_set_string(message, "file_path", url.fileSystemRepresentation);
Does not grant the XPC create/write permissions. Is there an API or trick I'm missing?
Note that the user should be allowed to save and create new files anywhere of their choosing, thus restricting URLs to only those within a group or container shared between the app and service isn't really viable.
Using the latest of everything on macOS with the xpc_session API...
2024-06-04 15:17:59.618853+0100 ProxyAgent[20233:29237510] [xpc.exceptions] <NSXPCConnection: 0x60000331cb40> connection from pid 20227 on anonymousListener or serviceListener: Exception caught during decoding of received selector newFlowWithIdentifier:to:type:metadata:socket:, dropping incoming message.
Exception: Exception while decoding argument 4 (#6 of invocation):
<NSInvocation: 0x600001778780>
return value: {v} void
target: {@} 0x0
selector: {:} null
argument 2: {@} 0x6000017787c0
argument 3: {@} 0x60000002d170
argument 4: {q} 1
argument 5: {@} 0x600001746600
argument 6: {@} 0x0
Exception: decodeObjectForKey: Object of class "NSFileHandle" returned nil from -initWithCoder: while being decoded for key <no key>
The extension is in Swift; the recipient is in ObjC (wheeeeee).
Based on the extension's logging, the FileHandle is not nil.
I am trying to pass a FileHandle based on a socketpair up to the user-land code. The sockets are created happily.
Any ideas what's going wrong here?
(Updated)
See replies below.
I create a protocol that had, among other things:
@objc func setList(_: [MyType], withReply: @escaping (Error?) -> Void)
The daemon part is in Swift, while the calling part is in Objective-C. Because why not? (Actually, because the calling part has to deal with C++ code, so that's ObjC++; however, I wanted the stronger typing and runtime checking for the daemon part, so I wrote it in Swift.) The ObjC part uses NSArray<MyType*>.
I set up an NSXPCConnection link, and create a (synchronous) proxy with the right protocol name. But when I try to do the XPC setList call, I get an error. I assume that's because it doesn't like the signature. (Surely this is logged somewhere? I couldn't find it, if so. 😩) But... if I have a signature of @objc func addItem(_: MyType, withReply: @escaping (Error?) -> Void), then it works. So I assume it's the array. (Oh, I've also tried it without the @objc; the protocol itself is defined as @objc.)
I've tried changing to protocol signature to using NSArray, but same thing.
Hi :wave:
I started a new project to experiment with EndpointSecurity framework.
It seems to have been worked, but when I try to add XPC I face some troubles.
I am not able to send XPC message from my app to my system extension.
No runtime error, but when I'm inspecting logs:
That correspond to this code: https://github.com/tony-go/TestES/blob/main/Extension/main.swift#L21-L30
Full project: https://github.com/tony-go/TestES/
I thought at first that it could come from a missing @objc somehere but it does not seems ...
I also wonder why I cannot catch this error at runtime ?
I'm using XPC to do IPC with an agent service.
I use NSXPCConnection initWithMachServiceName to create the connection and active it.
Then I get the agent service remote object proxy with method remoteObjectProxyWithErrorHandler. But when the agent service unloaded, I can also get the remote proxy without any error.
Is there anyway to check XPCConnection really connect to a XPC server?
Hi everyone,
first-time caller, long-ti... wait, no, I just got here. :)
I am relatively new to all things Apple, so apologies in advance if it takes me a few goes to properly explain things.
We have a framework, which includes an API, an XPC service, etc, and we have a device driver. We also have some sample apps that use the framework, and if they have the app sandbox capability, then we expect them to use the XPC Service instead of accessing our driver directly. This works fine on Monterey and presumably has worked fine on all previous versions of MacOS.
Something seems to have changed on Ventura, and we don't understand what.
When we build the same app on Ventura, it appears to be in the sandbox (according to the Sandbox column in Activity Monitor), but in the Console there is this line (twice):
default <time> <OurAppName> Revoking sandbox extension; key = 0
Which we suspect is linked to the fact that the app then does not use the XPC Service, and instead accesses the driver directly, much to our surprise.
Software built on developer's machines is "Automatically managed" and "Signed to Run Locally" in case that matters.
Do we need to change our code to support Ventura and onward? Or is it a bizarre bug?
Oh, I should say that I'm running the latest version of Ventura (13.6.7 as of writing) but not the latest Xcode (14.2 (14C18)) and CLI tools... can't remember how to find that version... Apple clang version 14.0.0 (clang-1400.0.29.202).
Any help would be appreciated, thanks.
Jeremy
I create a camera extension and App can push video data to camera extension with sinkStream. I want to monitor the number of clients connected to the camera extension and close the app's push stream when the number of connected client is zero.
I am attempting to install and utilize an agent using the new(ish) SMAppService API with an existing app. The agent appears to install (no error is returned), but when I try to start the agent from Terminal, I get the following in the launchd.log:
2024-04-22 09:57:27.469039 (gui/502/com.redacted.service.agent) : internal event: WILL_SPAWN, code = 0
2024-04-22 09:57:27.469080 (gui/502/com.redacted.service.agent) : service state: spawn scheduled
2024-04-22 09:57:27.469081 (gui/502/com.redacted.service.agent) : service state: spawning
2024-04-22 09:57:27.469100 (gui/502/com.redacted.service.agent) : launching: one-shot
2024-04-22 09:57:27.469105 (gui/502/com.redacted.service.agent) : Allowing non-reentrant proxy for resolving path
2024-04-22 09:57:27.469947 (gui/502/com.redacted.service.agent [71866]) : xpcproxy spawned with pid 71866
2024-04-22 09:57:27.469960 (gui/502/com.redacted.service.agent [71866]) : internal event: SPAWNED, code = 0
2024-04-22 09:57:27.469964 (gui/502/com.redacted.service.agent [71866]) : service state: xpcproxy
2024-04-22 09:57:27.469997 (gui/502/com.redacted.service.agent [71866]) : internal event: SOURCE_ATTACH, code = 0
2024-04-22 09:57:27.506283 (gui/502/com.redacted.service.agent [71866]) : Service could not initialize: posix_spawn(/Users/chrisf/Library/Developer/Xcode/DerivedData/Redacted-gttupgdyakodzddurpavhmscwabs/Build/Products/Debug/Redacted App.app/Contents/MacOS/Service Agent.app), error 0xd - Permission denied
2024-04-22 09:57:27.506306 (gui/502/com.redacted.service.agent [71866]) : initialization failure: 23E224: xpcproxy + 31420 [1098][A7EF179C-FBCC-349E-A7D2-09B2F1408413]: 0xd
2024-04-22 09:57:27.506309 (gui/502/com.redacted.service.agent [71866]) : internal event: INIT, code = 13
2024-04-22 09:57:27.506313 (gui/502/com.redacted.service.agent [71866]) : job state = spawn failed
2024-04-22 09:57:27.507148 (gui/502/com.redacted.service.agent [71866]) : xpcproxy exited due to exit(78)
2024-04-22 09:57:27.507153 (gui/502/com.redacted.service.agent [71866]) : exited due to exit(78)
2024-04-22 09:57:27.507162 (gui/502/com.redacted.service.agent [71866]) : already handled failed init, ignoring
2024-04-22 09:57:27.507170 (gui/502/com.redacted.service.agent [71866]) : service state: exited
2024-04-22 09:57:27.507186 (gui/502/com.redacted.service.agent [71866]) : internal event: EXITED, code = 0
(tldr: error 0xd - Permission denied)
I'd also be curious how we are expected to launch agents once registered with SMAppService. Is it sufficient simply to make an XPC call to an exposed method?
Thanks!
Hello Apple Developer Community,
I'm encountering an issue with my macOS application where I'm receiving the following error message:
Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.FxPlugTestXPC was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.FxPlugTestXPC was invalidated: failed at lookup with error 159 - Sandbox restriction.}
This error occurs when my application tries to establish a connection to an XPC service named com.FxPlugTestXPC. It appears to be related to a sandbox restriction, but I'm unsure how to resolve it.
I've checked the sandboxing entitlements and ensured that the necessary permissions are in place. However, the issue persists.
Has anyone encountered a similar error before? If so, could you please provide guidance on how to troubleshoot and resolve this issue?
Any help or insights would be greatly appreciated.
Thank you.
this is some photos about my entitlements :
I noticed a problem while writing a program using XPC on macOS.
When I write it in the form of a closure that receives the result of an XPC call, I can't receive it forever.
I add an XPC target in Xcode, the sample code is used in the pass closure format, but can't I use closure passing with XPC?
My Environment:
Xcode 15.3
macOS 14.4.1
caller (closure version)
struct ContentView: View {
@State var callbackResult: String = "Waiting…"
var body: some View {
Form {
Section("Run XPC Call with no argument and no return value using callback") {
Button("Run…") {
callbackResult = "Running…"
let service = NSXPCConnection(serviceName: "net.mtgto.example-nsxpc-throws-error.ExampleXpc")
service.remoteObjectInterface = NSXPCInterface(with: ExampleXpcProtocol.self)
service.activate()
guard let proxy = service.remoteObjectProxy as? any ExampleXpcProtocol else { return }
defer {
service.invalidate()
}
proxy.performCallback {
callbackResult = "Done"
}
}
Text(callbackResult)
...
}
}
}
callee (closure version)
@objc protocol ExampleXpcProtocol {
func performCallback(with reply: @escaping () -> Void)
}
class ExampleXpc: NSObject, ExampleXpcProtocol {
@objc func performCallback(with reply: @escaping () -> Void) {
reply()
}
}
I found this problem can be solved by receiving asynchronous using Swift Concurrency.
caller (async version)
struct ContentView: View {
@State var callbackResult: String = "Waiting…"
var body: some View {
Form {
Section("Run XPC Call with no argument and no return value using callback") {
Button("Run…") {
simpleAsyncResult = "Running…"
Task {
let service = NSXPCConnection(serviceName: "net.mtgto.example-nsxpc-throws-error.ExampleXpc")
service.remoteObjectInterface = NSXPCInterface(with: ExampleXpcProtocol.self)
service.activate()
guard let proxy = service.remoteObjectProxy as? any ExampleXpcProtocol else { return }
defer {
service.invalidate()
}
await proxy.performNothingAsync()
simpleAsyncResult = "DONE"
}
Text(simpleAsyncResult)
...
}
}
}
callee (async version)
@objc protocol ExampleXpcProtocol {
func performNothingAsync() async
}
class ExampleXpc: NSObject, ExampleXpcProtocol {
@objc func performNothingAsync() async {}
}
To simplify matters, I write source code that omits the arguments and return value, but it is not also invoked by using callback style.
All sample codes are available in
https://github.com/mtgto/example-nsxpc-throws-error
Development Environment:
Xcode Version: 14.3.1
macOS Ventura Version: 13.6.2
Architecture: Intel
I am developing a macOS app with an accompanying XPC service and am encountering an issue where the XPC connection is immediately invalidated upon trying to establish it. The error message received is:
Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.appname.macos.app-name-xpc was invalidated." UserInfo={NSDebugDescription=The connection to service named com.appname.macos.app-name-xpc was invalidated: failed at lookup with error 3 - No such process.}
Here's what I have verified so far:
The XPC service has the correct CFBundleIdentifier and is located within the Contents/XPCServices directory of my app's bundle.
Info.plist for the XPC service has ServiceType set to Bundled.
The XPC service target's Installation Directory is the default location for XPC services (@executable_path/../XPCServices).
Code signing and entitlements have been verified for both the main app and the XPC service, and disabling the sandbox doesn't resolve the issue.
The main app and XPC service are part of the same App Group, and both have the App Sandbox capability enabled.
Here's a snippet of the Swift code that establishes the XPC connection:
let xpcConnection = NSXPCConnection(serviceName: "com.appname.macos.app-name-xpc")
xpcConnection.remoteObjectInterface = NSXPCInterface(with: ServiceProtocol.self)
xpcConnection.resume()
And here's the ServiceProtocol for reference:
@objc public protocol ServiceProtocol: NSObjectProtocol {
@objc func executeUnixExecutable(arguments: [String], completionHandler: @escaping (ResultType) -> Void)
func interruptUnixExecutable()
func closeUnixExecutablePipes()
}
When I run the app, the connection is invalidated without any further details as to why. I'm not sure if I'm missing a configuration step or if there's an issue with my XPC service setup.
Has anyone experienced this issue or have suggestions on what else I can check to resolve this?
I've been experimenting with the new low-level Swift API for XPC (XPCSession and XPCListener). The ability to send and receive Codable messages is an appealing alternative to making an @objc protocol in order to use NSXPCConnection from Swift — I can easily create an enum type whose cases map onto the protocol's methods.
But our current XPC code validates the incoming connection using techniques similar to those described in Quinn's "Apple Recommended" response to the "Validating Signature Of XPC Process" thread. I haven't been able to determine how to do this with XPCListener; neither the documentation nor the Swift interface have yielded any insight.
The Creating XPC Services article suggests using Xcode's XPC Service template, which contains this code:
let listener = try XPCListener(service: serviceName) { request in
request.accept { message in
performCalculation(with: message)
}
}
The apparent intent is to inspect the incoming request and decide whether to accept it or reject it, but there aren't any properties on IncomingSessionRequest that would allow the service to make that decision. Ideally, there would be a way to evaluate a code signing requirement, or at least obtain the audit token of the requesting process.
(I did notice that a function xpc_listener_set_peer_code_signing_requirement was added in macOS 14.4, but it takes an xpc_listener_t argument and I can't tell whether XPCListener is bridged to that type.)
Am I missing something obvious, or is there a gap in the functionality of XPCListener and IncomingSessionRequest?