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
48 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
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?
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!
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
This thread has an accepted response.
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 have an application, it has main process and some child processes. As we want those child processes to have their own minimum sandbox privilege, not inheriting from parent process, we plan to use XPCService which uses a NSTask to launch those child processes, so those child processes can have its own sandbox privilege.
We plan to deliver the application to Mac App Store, so process mode is: the sandboxed main process builds connections to the unsandboxed XPCService, the unsandboxed XPCService launch those sandboxed child processes.
Can this process mode pass the Mac App Store rules? I see, there is a rule that all processes must be sandboxed, including XPCService. But I tested locally, the Application downloaded from Mac apple store also launches unsandboxed XPCService, like OneDrive.
Do you have any suggestions for my application scenario, sandboxed child processes having its own privilege not inheriting from parent?
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?
We are working on a command line daemon (started with launchd) for a UI to communicate with using XPC. The functions we have been using so far work correctly, but they only take arguments and return void.
We wanted to add a function with a simple reply block to see if the daemon is running or not, and we may need to get data back in the future. But it is not working.
For example, this is working:
if let proxy = connectionToService.remoteObjectProxyWithErrorHandler({ error in
print(error.localizedDescription)
}) as? TheDaemonProtocol {
proxy.doStuff("Test string")
}
But this returns an error "Couldn’t communicate with a helper application."
if let proxy = connectionToService.remoteObjectProxyWithErrorHandler({ error in
print(error.localizedDescription)
}) as? TheDaemonProtocol {
proxy.isUp { reply in
print("reply: \(reply)")
}
}
isUp() is coded to only return true for now.
@objc func isUp(reply: @escaping (Bool) -> Void) {
reply(true)
}
TIA for any help!
I'm working on a macOS application that deals with a few external dependencies that can only be compiled for intel (x86_64) but I want the app to run natively on both arm and x86_64.
One idea I have been playing with is to move the x86_64 dependencies to an xpc service compiled only as x86_64 and use the service only the intel machine. However, I can't figure out how to setup my project to compile everything at once...
Any ideas? Is this even possible? If not, I'm open to suggestions...
Thanks
Greetings!
I've added a Matter accessory via the Apple Home app. In my app, I'm attempting to commission this device and add it to my fabric. However, when I try to open the commissioning window, I receive an error stating, MTRBaseDevice doesn't support openCommissioningWindowWithDiscriminator over XPC.
It appears that opening a commissioning window via an XPC connection is not yet supported. Is there another method to commission the device? Can I retrieve the setup payload from the MTRBaseDevice object or the shared MTRDeviceController?
Here's the simplified version of my code:
var home: HMHome // HMHome received via HMHomeManager
var accessory: HMAccessory = home.accessory[0] // my Matter-supported accessory
let deviceController = MTRDeviceController.sharedController(
withID: home.matterControllerID as NSCopying,
xpcConnect: home.matterControllerXPCConnectBlock
)
let device = MTRBaseDevice(
nodeID: accessory.matterNodeID as NSNumber,
controller: deviceController
)
device.openCommissioningWindow(
withDiscriminator: 0,
duration: 900,
queue: .main) { payload, error in
if let payload {
// payload not received
} else if let error {
// I'm getting here "Error Domain=MTRErrorDomain Code=6 "(null)""
// and "MTRBaseDevice doesn't support openCommissioningWindowWithDiscriminator over XPC" logged in the console
print(error)
}
I am currently working on planning a multi-component software system that consists of an Audio Server Plugin and an application for user interaction. I have very little experience with IPC/XPC and its performance implications, so I hope I can find a little guidance here.
The Audio Server plugin publishes a number of multi-channel output devices on which it should perform computations and pass the result on to a different Core Audio device. My concerns here are:
Can the plugin directly access other CoreAudio devices for audio output or is this prohibited by the sandboxing? If it cannot, would relaying the audio data via XPC be a good idea in terms of low latency stability?
Can I use metal compute from within the Audio Server plugin? I have not found any information about metal related sandboxing entitlements. I am also concerned about performance implications as above.
Regarding the user interface application, I would like to know:
If a process that has not been started by launchd can communicate with the Audio Server plugin using XPC. If not, would a user agent instead of an app be a better choice? Or are there other communication channels that would work with sandboxing?
Thank you very much!
Andreas
I want to
build an Xcode Source Code Editor extension
that triggers an XPC service
shows a gui that can handle user interactions
Is it possible in any way ?
what are the alternatives to display the UI and allow the user to interact on it ?
Hello,
we are currently working on a plan to migrate our app suite from Developer ID binaries inside a simple pkg installer to macOS app store distribution.
The reason we are using an installer is that there are multiple binaries inside that communicate via XPC and we need to install the respective launchd plist in /Library/LaunchDaemons and /Library/LaunchAgents:
1 root daemon
1 agent that has minimal UI and lives in the system menu bar
1 embedded command line utility in user agent
1 embedded FileProvider extension in user agent
1 embedded Action Extension in user agent
1 agent that only does OAuth stuff
Looking through Updating helper executables from earlier versions of macOS I can install the root daemon with SMAppService.daemon(plistName:) and the OAuth helper with SMAppService.agent(plistName:). For the main application I only found SMAppService.mainApp which does not accept a property list configuration. Therefore, I have no place to put my MachServices array and so the File Provider extension, the Action Extension, and the embedded command line utility have no way to talk to the user agent.
Currently, XPC is used in between these processes:
user agent -> root daemon
command line utility -> user agent
action extension -> user agent
file provider extension -> user agent
user agent -> file provider extension: that already works through NSFileProviderServicing
I know app-to-app communication only works through launchd for security reasons, but these applications are all part of the same app group (except the root daemon obviously).
My question is what is the proper way of starting the user agent so XPC from other binaries just work ™️?
Any input is much appreciated!
I asked a similar question last year, and got no responses. I've written a much simpler (no network extension!) case that seems to demonstrate what I'm confused about.
Simple app with an XPC service. I have an ObjectiveC class TestObject which has an NSString* and an NSData* (which I never actually use). I have a protocol defined in Swift:
@objc protocol XPCTestServiceProtocol {
func logData(entry: TestObject) -> Void
func logData(entry: TestObject, completion: ((String) -> Void))
}
In the Switt XPC service, the code is:
class XPCTestService: NSObject, XPCTestServiceProtocol {
var totalBytes = 0
var lastName = ""
@objc func logData(entry: TestObject) {
totalBytes += (entry.data?.count ?? 0)
}
@objc func logData(entry: TestObject, completion: ((String) -> Void)) {
totalBytes += (entry.data?.count ?? 0)
completion("Finished")
}
I've got this code in the ObjC app:
id<XPCTestServiceProtocol> proxy = [self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) {
self.stopRun = YES;
NSLog(@"Proxy got error %@", error);
}];
while (self.stopRun == NO) {
@synchronized (self) {
NSNumber *objNum = [NSNumber numberWithUnsignedLongLong:self.count++];
NSString *objName = [NSString stringWithFormat:@"Object %@", objNum];
TestObject __weak *toWeak = to;
#if USE_COMPLETION
[proxy logDataWithEntry:to completion:^(NSString *str) {
to = nil;
}];
#else
[proxy logDataWithEntry:to];
#endif
}
}
attached to a start button (and self.stopRun is set by a stop button, this is all super simple).
So I run that, start the test, and things start going (122k calls/second it says). According to Activity Monitor, my app is using about 1gbyte after 20 seconds or so.
However, if I run it under Instruments' Leaks template... Activity Monitor says it's used only about 60mbytes. (And at the end of the run, Instruments says it's used about 30mbytes.)
Now... if I use the completion and a synchronous proxy, then even without Instruments, Activity Monitor says it's 60mbytes or so.
Is the memory reported by Activity Monitor real? Or not real?
Hi there :)
I try to put an Xcode project in place within a LaunchAgent.
The ultimate goal is to have an "application" with two component:
macOS application with just an basic UI
all the logic happens in a LaunchAgent that runs on background and is launch at startup.
The macOS app uses XPC to send messages to the agent that will run either the app is opened or not.
I struggled at first having this error (for the agent):
An XPC Service cannot be run directly.
Then I found using MachServices key in the .plist of the agent fixes the issue, plus:
let listener = NSXPCListener.init(machServiceName: "com.tonygo.NetworkMonitorAgent")
Then I wonder:
Do we have somewhere a documentation about how to setup a LaunchAgent in Xcode
I create the plist of the agent on side and run it manually, I could do this in a more automatic way
How could I package a macOS applciation that will contains the agent, install it and load the agent?
Note: This is mainly for learning and understanding what we could do at each level (XPCService, LaunchAgents, LaunchDaemon, etc.).
Hi everyone :)
I'm exploring XPC these days; more specifically, I'm trying to establish a connection between a macOS application and an XPC service.
I succeeded in establishing the connection, but now I'm trying to verify the incoming connection by using SecCodeCopyGuestWithAttributes, passing it an audit token.
But I got the following error:
2024-01-18 10:43:06.805435+0100 DemoService[1627:7118397] [logging-persist] cannot open file at line 46922 of [554764a6e7]
2024-01-18 10:43:06.805452+0100 DemoService[1627:7118397] [logging-persist] os_unix.c:46922: (0) open(/private/var/db/DetachedSignatures) - Undefined error: 0
Cannot get SecCode: 100001 - UNIX[Operation not permitted]
Audit token: Optional(32 bytes)
The last two lines come from my code:
class XPCClientValidator {
var secCodeOptional: SecCode? = nil;
func identifyGuest(for connection: NSXPCConnection) -> Bool {
let auditToken = AuditToken.extractToken(from: connection)
let hostSecCode: SecCode? = nil; // This is a way to indicate that the code signing root of trust hould be used as host.
let attributes = [ kSecGuestAttributeAudit: auditToken ] as CFDictionary
let secFlags = SecCSFlags(rawValue: 0)
// Asks a code host to identify the guest given the audit token
let status: OSStatus = SecCodeCopyGuestWithAttributes(hostSecCode, attributes, secFlags, &self.secCodeOptional)
if (status != errSecSuccess) {
let msg = SecCopyErrorMessageString(status, nil)!
print("Cannot get SecCode: \(status) - \(msg)")
print("Audit token: \(String(describing: auditToken))")
return false
}
guard let _ = secCodeOptional else {
NSLog("Couldn't unwrap the secCode")
return false
}
return true
}
}
I saw a few posts on the forum, but nothing helped me to solve this issue.
The complete source code is here: https://github.com/tony-go/XPCDemo/tree/secure-xpc
Note: If you want to reproduce it, you have to:
start the app
type a random input
click on "uppercase it"
I am looking for a solution to transfer data between two completely separate processes (not from the same group). I did a lot of research, but the solutions were mostly for processes that are in a group. Is there a method? (It doesn't matter if the app is sandboxed, I can disable it).
My goal is to communicate between a bundle(plugin) that is activated on the Mac login page and an XPC service and transfer data from the service to the bundle.