XPC is a a low-level (libSystem) interprocess communication mechanism that is based on serialized property lists.

Posts under XPC tag

200 Posts

Post

Replies

Boosts

Views

Activity

[XPC] Are there errors that are only reported to a send message replyBlock?
Context The event handler of an xpc_connection_t object named myConnection is set and handles XPC_TYPE_ERROR objects: xpc_connection_set_event_handler(myConnection, ^(xpc_object_t object) { }); A message is sent using: xpc_connection_send_message_with_reply(myConnection, myMessage , myQueue, ^(xpc_object_t object) { }); The documentation for the well-known XPC_ERROR_ dictionaries and for xpc_connection_set_event_handler seems to suggest that all the errors received via the reply block will also be received by the event handler. Question Are there error cases where only the reply block of xpc_connection_send_message_with_reply will receive an XPC_ERROR*_ object?
1
0
1.5k
Jan ’23
Troubleshooting the launch of local user XPC Launch Agent
This is a follow up to the thread, Troubleshooting the launch of local user XPC Launch Agent, in the original (and now archived) Dev Forums.Based on further tests, I assume there must be some configuration that I'm not setting up correctly, as opposed to the code.I started from scratch again with a fresh Xcode Project. This time, I based the code mostly on the example code posted by Apple Engineer eskimo1 in this thread (which uses an privileged Launch Daemon) with a modification or two based on the code posted by Apple Engineer dsorresso in this thread. As I assume that their code can be expected to work (i.e.- to help rule out a coding error on my part). Except that I modified the code so that it works with/as an XPC Service Launch Agent without the privileged aspect and which resides inside of the user's home directory.The following was all done on OS X 10.10.3 (14D136) Yosemite and built with Xcode 6.3.2 (6D2105).* I first started off both the command line interface program and the XPC Service Launch Agent without Code Signing or Sandboxing. When the command line interface program was run at the command line, I got output such as the following. Which more or less resembles the behaviour I was seeing with my own test code.connection event error Connection invalid* Then I code signed both items. No change in the output.* Next, I Sandboxed both. While there was no change in the output at the command line, some entries containing 'deny mach-lookup' began to appear in the System Console logs -> in asl -> with the AUX prefix. e.g.CLIHelloToLaunch(6103) deny mach-lookup com.test.XPCLA* Later, I added a com.apple.security.temporary-exception.mach-lookup.global-name key of Type Array containing the Bundle Identifier of the XPC Service Launch Agent in the Entitlements files for both Targets. No change in the command line output and 'deny mach-lookup' entries still appeared in System Console logs -> asl -> AUX.* As well, I also added an App Group to the Entitlements files for both Targets. No change in the command line output and 'deny mach-lookup' entries still appeared in System Console logs -> asl -> AUX.What could be the cause of the XPC connection errors? I presume that the 'deny mach-lookup' entries are related. How can I fix this?This is the contents of the launchd plist file for the XPC Service Launch Agent. It resides in ~/Library/LaunchAgents:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.test.XPCLA</string> <key>MachService</key> <dict> <key>com.test.XPCLA</key> <true/> </dict> <key>ProgramArguments</key> <array> <string>~/Library/Application Support/com.test.XPCLA.xpc</string> </array> </dict> </plist>This is the code being used in the XPC Service Launch Agent. Specifically, in it's main.m file. After building, I put the .xpc Launch Agent in ~/Library/Application Support for testing.#import <Foundation/Foundation.h> #include <xpc/xpc.h> static void SetupConnection(xpc_connection_t connection) { xpc_connection_set_event_handler(connection, ^(xpc_object_t object) { if ( xpc_get_type(object) == XPC_TYPE_ERROR ) { fprintf(stderr, "connection error %s\n", xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION)); xpc_connection_cancel(connection); } else if ( xpc_get_type(object) == XPC_TYPE_DICTIONARY ) { const char * name; fprintf(stderr, "connection message\n"); name = xpc_dictionary_get_string(object, "name"); if (name == NULL) { fprintf(stderr, "no name\n"); xpc_connection_cancel(connection); } else { xpc_object_t response; char * responseStr; fprintf(stderr, "name is '%s'\n", name); (void) asprintf(&responseStr, "hello %s", name); response = xpc_dictionary_create(NULL, NULL, 0); assert(response != NULL); xpc_dictionary_set_string(response, "greeting", responseStr); xpc_connection_send_message(connection, response); // xpc_release(response); } } else { assert(false); } }); xpc_connection_resume(connection); } int main(int argc, char** argv) { xpc_connection_t listener; fprintf(stderr, "XPC Helper start\n"); listener = xpc_connection_create_mach_service("com.test.XPCLA", NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); assert(listener != NULL); xpc_connection_set_event_handler(listener, ^(xpc_object_t object) { if ( xpc_get_type(object) == XPC_TYPE_ERROR ) { fprintf(stderr, "listener error\n"); // XPC_ERROR_KEY_DESCRIPTION } else if ( xpc_get_type(object) == XPC_TYPE_CONNECTION ) { fprintf(stderr, "listener connection\n"); SetupConnection(object); } else { assert(false); } }); xpc_connection_resume(listener); dispatch_main(); return EXIT_SUCCESS; }This is the code in the command line interface program's main.m file. After building, I put the program into ~/Applications.#import <Foundation/Foundation.h> #include <xpc/xpc.h> static BOOL Test(void) { BOOL success; xpc_connection_t connection; xpc_object_t request; xpc_object_t response; response = NULL; connection = xpc_connection_create_mach_service("com.test.XPCLA", NULL, 0); assert(connection != NULL); request = xpc_dictionary_create(NULL, NULL, 0); assert(request != NULL); xpc_dictionary_set_string(request, "name", "Hello service, this is the program speaking, are you out there?"); xpc_connection_set_event_handler(connection, ^(xpc_object_t object) { fprintf(stderr, "connection event\n"); if ( xpc_get_type(object) == XPC_TYPE_ERROR ) { fprintf(stderr, "error %s\n", xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION)); } else if ( xpc_get_type(object) == XPC_TYPE_DICTIONARY ) { const char * greeting; fprintf(stderr, "response\n"); greeting = xpc_dictionary_get_string(object, "greeting"); fprintf(stderr, "greeting is '%s'\n", greeting); } else { fprintf(stderr, "something else\n"); } }); xpc_connection_resume(connection); xpc_connection_send_message(connection, request); dispatch_main(); if (request != NULL) { xpc_release(request); } if (response != NULL) { xpc_release(response); } return success; } int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"%@", @"About to run test of XPC Service."); Test(); } return 0; }Here are the command line program's Entitlements.<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.app-sandbox</key> <true/> <key>com.apple.security.temporary-exception.mach-lookup.global-name </key> <array> <string>com.test.XPCLA</string> </array> <key>com.apple.security.application-groups</key> <array> <string>$(TeamIdentifierPrefix)IPC</string> </array> </dict> </plist>The XPC Service Launch Agent's Entitlements.<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.app-sandbox</key> <true/> <key>com.apple.security.application-groups</key> <array> <string>$(TeamIdentifierPrefix)IPC</string> </array> <key>com.apple.security.temporary-exception.mach-lookup.global-name </key> <array> <string>com.test.XPCLA</string> </array> </dict> </plist>Additional notes, if it's relevant:* The command line interface program has an embedded info.plist since it's a single file executable.* Command line interface program was created via Xcode 6.3.2's New Target -> Command Line Tool template* XPC Service was created via Xcode 6.3.2's New Target -> XPC Service template.
10
0
8.6k
Jan ’23
XPC and ARC?
xctrace --template Leaks identified this as a leak:         NSString *uuid = [NSString stringWithUTF8String:connectionID];         NSData *contentData = [NSData dataWithBytes:data length:length];         id<ConnexctionProtocol> proxy = [connection asyncConnectionProxy];         [proxy handleData:uuid data:contentData]; return; (Which is to say: a few thousand objects show up in the Leaks pane, the stack for them goes up to the NSData creation, and Leaks apparently thinks it's never released.) That doesn't look like it should be a leak, with ARC? Which probably means I'm doing something wrong?
0
0
722
Dec ’22
Need help resolving a nasty crash
Two Obj-C processes A and B, communicating via XPC, using NSXPCConnection (the connection is created from an endpoint, unnamed). The method signature is this: - (void)userAction:(NSString *)identifier             update:(OITNFWPreventionStage)stage          eventInfo:(NSDictionary * _Nonnull)actionInfo          withError:(NSError * _Nullable)error              reply:(void (^ _Nullable)(BOOL))reply; I'm using a normal asynchronous proxy id<myProtocol> monitorProxy = [self.monitorConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {         NSLog( @"Monitoring XPC proxy call failed: %@", error);     }]; Since the actionInfo I'm using is NSMutableDictionary the gets updated frequently from concurrent queues and thread - I synchronize ALL my calls from process A to process B on an NSOperationQueue     NSOperationQueue *monitorUpdateQueue = [[NSOperationQueue alloc] init];     monitorUpdateQueue.name = @"monitoring queue";     monitorUpdateQueue.maxConcurrentOperationCount = 1;     monitorUpdateQueue.qualityOfService = NSQualityOfServiceUtility; My calls typically look like this:     [monitorUpdateQueue addOperationWithBlock:^{         actionInfo[@"Files"] = [fileEvents valueForKeyPath:@"dictionary"]; // some NSArray of NSDictionaries         actionInfo[@"stage"] = ActionStagePreblocked;         [monitorProxy userAction:userActionIdentifier update:ActionStagePreblocked eventInfo:actionInfo withError:nil reply:^(BOOL reported) {             NSLog(@"Action reported");         }];     }]; Now every now and then, Process A (the caller) crashes inside this remote call... I Full crash log. Couldn't attach .ips file Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: KERN_INVALID_ADDRESS at 0x00004c52f8b94400 Exception Codes: 0x0000000000000001, 0x00004c52f8b94400 Exception Note: EXC_CORPSE_NOTIFY Termination Reason: Namespace SIGNAL, Code 11 Segmentation fault: 11 Terminating Process: exc handler [83282] VM Region Info: 0x4c52f8b94400 is not in any region. Bytes after previous region: 83438207583233 Bytes before following region: 21633872346112 REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL commpage (reserved) 1000000000-7000000000 [384.0G] ---/--- SM=NUL ...(unallocated) ---> GAP OF 0x5f9000000000 BYTES MALLOC_NANO 600000000000-600008000000 [128.0M] rw-/rwx SM=PRV and the thread's stack looks like this: Thread 10 Crashed:: Dispatch queue: monitoring queue (QOS: UTILITY) 0 libobjc.A.dylib 0x18a7e8310 objc_retain + 16 1 Foundation 0x18b8eb4a8 -[NSDictionary(NSDictionary) encodeWithCoder:] + 596 2 Foundation 0x18b8ba5f4 -[NSXPCEncoder _encodeObject:] + 520 3 Foundation 0x18b8b9ae4 _NSXPCSerializationAddInvocationArgumentsArray + 276 4 Foundation 0x18b8b95fc -[NSXPCEncoder _encodeInvocation:isReply:into:] + 256 5 Foundation 0x18b8b8798 -[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:] + 1356 6 CoreFoundation 0x18aa08040 ___forwarding___ + 1088 7 CoreFoundation 0x18aa07b40 _CF_forwarding_prep_0 + 96 8 myproc 0x10041370c __84-[myproc scanContentOfFilesInEvents:userActionInfo:monitorProxy:monitoringQueue:]_block_invoke_2.1588 + 1064 (myproc.m:3690) 9 Foundation 0x18b8e0600 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 24 10 Foundation 0x18b8e04a8 -[NSBlockOperation main] + 104 11 Foundation 0x18b8e0438 __NSOPERATION_IS_INVOKING_MAIN__ + 24 12 Foundation 0x18b8df67c -[NSOperation start] + 804 13 Foundation 0x18b8df350 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 24 14 Foundation 0x18b8df204 __NSOQSchedule_f + 184 15 libdispatch.dylib 0x18a7ad990 _dispatch_block_async_invoke2 + 148 16 libdispatch.dylib 0x18a79ebac _dispatch_client_callout + 20 17 libdispatch.dylib 0x18a7a2080 _dispatch_continuation_pop + 504 18 libdispatch.dylib 0x18a7a16dc _dispatch_async_redirect_invoke + 596 19 libdispatch.dylib 0x18a7b031c _dispatch_root_queue_drain + 396 20 libdispatch.dylib 0x18a7b0b58 _dispatch_worker_thread2 + 164 21 libsystem_pthread.dylib 0x18a959574 _pthread_wqthread + 228 22 libsystem_pthread.dylib 0x18a9582c4 start_wqthread + 8 Sorry for the terrible formatting, I could not attach the .ips file, but I attached its full text. My question: When I'm passing an NSMutableDictionary to the remote proxy. Is it received "mutable" on the other side? and while it is being worked in on the receiving side, what happens if I modify it on the calling side (process A) ? How do Mutable objects behave on XPC calls? The Dictionary I'm moving only contains basic "plist approved" entries - NSString, NSNumber, NSDate, and collections (NSArray, NSDictionary). That's all. No custom classes there. I will be most grateful for any idea or hint.
3
0
3.7k
Dec ’22
Notification on NSUserDefaults Change When App Is In Background
I have two applications that share an app group @"group.edu.tds.poc.shared"Using NSUserDefaults of this app group, I am able to exchange data between the reader app and the writer app.The Writer App writes data to the NSUserDefaultNSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.edu.tds.poc.shared"]; [share dDefaults setObject:stringToStore forKey:key]; [sharedDefaults synchronize];The Reader App reads the data from the NSUserDefaultNSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.edu.tds.poc.shared"]; return [sharedDefaults stringForKey:@"key"];I now want the reader app to be notified as soon as the writer app modifies the value for the key. I.e. Can I notify the reader app when the writer app is running in the foreground (Reader app is either running in the background or is not running).I have implemented the marked solution but with no luck:Cocoa - Notification on NSUserDefaults value change?NSUserDefaults and KVO issuesCall back only when the Reader App is in foreground state. (Wrote to the Shared Defaults using Reader app)Any idea if this can be achieved?
6
1
3.1k
Nov ’22
Communicating between System Extension (specifically, camera extension) and Container App
i am trying to send data from the container app to its system extension (specifically, a camera extension. i am not entirely sure how to go about this. i read that i could utilize XPC, and i have tried this but for some reason, the system extension returns nothing when trying to connect to the XPC Service. below is an example code snipper let connectionToService = NSXPCConnection(serviceName: "example.VirtualCameraXPC")     connectionToService.remoteObjectInterface = NSXPCInterface(with:VirtualCameraXPCProtocol.self)     connectionToService.resume() //checking processes available shows that the XPC Server process is never activated also. if let proxy = connectionToService.remoteObjectProxy as? VirtualCameraXPCProtocol {       proxy.getNewString() { aString in //this is never logged.         NSLog("Second result string was: \(aString)")       }     } when i run the above code from the container app, it works properly but from the system extension, i run into the problems commented above in the code block. i would appreciate any help that will help me successfully send data from my container app to my camera extension.
1
0
1.3k
Nov ’22
Communication between system extension and the app
I have a working NEPacketTunnelProvider app extension macOS app on the App Store. The company wants to explore the possibility of switching to system extension, so that we can distribute the app outside of the appstore too. I managed to do the switch and the extension works. But the communication is broken. DistributedNotificationCenter stopped working for me after switching to system extension, events are not received and I don't see any errors so I cannot say what's wrong. I tried to adopt XPC from this Filtering Network Traffic Apple's sample, but I get sandbox error - domain code 4099, failed at lookup with error 159 - Sandbox restriction. I get the same error if I try to run the sample with my company team id. I do these changes: NEMachServiceName to $(TeamIdentifierPrefix)com.mycompanyname.macos.dev App Groups to $(TeamIdentifierPrefix)com.mycompanyname.macos.dev Bundle ids to com.mycompanyname.macos.dev and com.mycompanyname.macos.dev.tunnelprovider com.mycompanyname.macos.dev has capabilities - App Groups, Network Extensions, System Extensions com.mycompanyname.macos.dev.tunnelprovider - Network Extensions, System Extensions Could you help me find the reason why DistributedNotificationCenter could stop receiving notifications? Or are you able to run Apple's sample? What changes do you make to run it under your team? Because it looks like my changes are wrong Either DistributedNotificationCenter or XPC would solve my problem
3
1
1.5k
Nov ’22
XPC Connection Not Invalidated on NSXPCListenerDelegate Denial
I am attempting to understand the expected behavior of several points related to XPC. Mainly, I have the following questions: Should I expect that NSXPCConnection.remoteObjectProxyWithErrorHandler to call the error handler if the associated NSXPCListenerDelegate returns false in its listener function? Does the error handler get called immediately if the remoteObjectProxyWithErrorHandler function fails? What does remoteObjectProxy return if an actual proxy object is never exported on the service-side (in the listener function)? Should I expect that NSXPCConnection.invalidate() and/or the connection's invalidationHandler to be called when the associated NSXPCListenerDelegate returns false in its listener function? According to the listener documentation below, it appears the listener function is supposed to invalidate the connection; however, I am not seeing this be the case. https://developer.apple.com/documentation/foundation/nsxpclistenerdelegate/1410381-listener To reject the connect, return a value of false. This causes the connection object to be invalidated. I have written a test that exhibits the fact when the listener function returns false, rather than the invalidationHandler being called, the interruptionHandler is called. import XCTest final class InvalidateTest: XCTestCase {   func testConnectionIsInvalidatedOnListenerRejection() {     //set up anonymous XPC Listener     let listener = NSXPCListener.anonymous()     let listenerDelegate = MockListenerDelegate()     listener.delegate = listenerDelegate     listener.resume()           //establish connection to service     let clientConnection = MockConnection(listenerEndpoint: listener.endpoint)     var interruptHandlerCalled = false     var invalidateHandlerCalled = false     let interruptionHandler = { interruptHandlerCalled = true }     let invalidationHandler = { invalidateHandlerCalled = true }     clientConnection.interruptionHandler = interruptionHandler     clientConnection.invalidationHandler = invalidationHandler     clientConnection.remoteObjectInterface = NSXPCInterface(with: XPCServDelegate.self)     clientConnection.exportedInterface = NSXPCInterface(with: XPCCliDelegate.self)     clientConnection.exportedObject = XPCCDelegate()     clientConnection.resume()           // get the proxy delegate to make the XPC pulse call     guard let proxy = clientConnection.remoteObjectProxy() as? XPCServDelegate else {       XCTAssert(false, "Unable to get proxy object")       return     }     // why is it not failing to get a proxy object in this case?           // make the pulse call     var replyCalled = false     let semaphore = DispatchSemaphore(value: 0)     proxy.pulse(reply: {       replyCalled = true       semaphore.signal()     })           let waitResult = semaphore.wait(timeout: .now() + 1)     XCTAssertEqual(waitResult, .timedOut)     XCTAssertFalse(replyCalled)           // why do these assertions fail?     XCTAssertTrue(clientConnection.invalidateCalled)     XCTAssertTrue(invalidateHandlerCalled)     XCTAssertFalse(interruptHandlerCalled)   } } @objc public protocol XPCServDelegate {   func pulse(reply: @escaping () -> Void) } class XPCSDelegate : XPCServDelegate {   func pulse(reply: @escaping () -> Void) {     reply()   } } @objc public protocol XPCCliDelegate {} class XPCCDelegate : XPCCliDelegate {} fileprivate class MockConnection : NSXPCConnection {   var invalidateCalled = false       override func invalidate() {     invalidateCalled = true     super.invalidate()   } } fileprivate class MockListenerDelegate : NSObject, NSXPCListenerDelegate {   func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {     return false   } }
0
0
1.8k
Nov ’22
XPC between Container App and System Extension
I'm trying to create an XPC service to communicate between my Endpoint Security Extension and its Container App. I've taken the Sample Endpoint App from here. I've then followed the steps under Creating the Service here In fact, when I added the XPC service via the template, Xcode automatically added an Embed XPC Services phase to the container app. I can confirm that in the built container app I see the xpc service: SampleEndpointApp.app/Contents/XPCServices/Service.xpc If I initiate an NSXPCConnection from the container app then I can both connect and make RPCs. Furthermore I see the service process running via ps and also launchtl. If however I try to initiate an NSXPCConnection from the extension then I see nothing. RPC doesn't work and I don't see the service being launched. I've tried this with and without the connection in the main app. What am I missing here? What needs to be done to allow both processes to talk to each other? Is there some permissions issue here? Note that my plist for the service is as follows:
13
0
3.8k
Oct ’22
How to publish an XPC Service in a global daemon that employs EndpointSecurity framework?
I have a global daemon managed by launchd, whose .plist is installed in /Library/LaunchDaemons). To be correctly entitled and code-signed so it can communicate with EndpointSecurity framework, its executable resides in a normal Mac App bundle (main() will run as minimal UI when launched from UI, and as a daemon when launched by launchd). This means that the ProgramArguments.0 in its .plist looks something like /Library/PrivilegedHelperTools/MyDaemonApp.app/Contents/MacOS/MyDaemonApp Now I need this daemon to publish an XPC Service (with few control commands) so that other components of our system (UI app, a user-context launchd-daemon and another launchd global-daemon) will be able to connect to The XPC Service and control it via the published protocol. I read some answers here, and also found a working order sample code that does just this here - https://github.com/jdspoone/SampleOSXLaunchDaemon But when I apply its content to my global daemon, word for word - it doesn't work - meaning, clients cannot create a connection to The XPC Service. The daemon is up and running, and functional. its .plist is quite simple and looks like this: <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.mycompany.itm.service</string> <key>KeepAlive</key> <true/> <key>RunAtLoad</key> <true/> <key>MachServices</key> <dict> <key>com.mycompany.itm.service</key> <true/> </dict> <key>ProgramArguments</key> <array> <string>/Library/PrivilegedHelperTools/IMyDaemonApp.app/Contents/MacOS/MyDaemonApp</string> <string>-monitor</string> <string>-protectDeviceProtocol</string> <string>USB</string> </array> </dict> </plist> It creates and starts an XPC listener in MYXPCListener.h like thus: #import <Foundation/Foundation.h> #import "MYXPCProtocol.h" NS_ASSUME_NONNULL_BEGIN @interface OITPreventionXPCService : NSObject (instancetype) init; (void) start; /* Begin listening for incoming XPC connections */ (void) stop; /* Stop listening for incoming XPC connections */ @end NS_ASSUME_NONNULL_END and the implementation is: /* AppDelegate.m */ @interface MYXPCService () <NSXPCListenerDelegate, OITPreventionXPCProtocol> @property (nonatomic, strong, readwrite) NSXPCListener *listener; @property (nonatomic, readwrite) BOOL started; @end @implementation OITPreventionXPCService (instancetype) init {     if ((self = [super init]) != nil) {         _listener = [[NSXPCListener alloc] initWithMachServiceName:@"com.mycompany.itm.service"];         _listener.delegate = self;         if (_listener == nil) {             os_log_error(myLog, "XPCListener failed to initialize");         }         _started = NO;     }     return self; } (void) start {     assert(_started == NO);     [_listener resume];     os_log_info(myLog, "XPCListener resumed");     _started = YES; } (void) stop {     assert(_started == YES);     [_listener suspend];     os_log_info(myLog, "XPCListener suspended");     _started = NO; } /* NSXPCListenerDelegate implementation */ (BOOL) listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {     os_log_info(myLog, "Prevention XPCListener is bequsted a new connection");     assert(listener == _listener);     assert(newConnection != nil);     newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MYXPCProtocol)];     newConnection.exportedObject = self; &#9;&#9;[newConnection resume];     return YES; } /* Further down this implementation, I have implementations to all the methods in MYXPCProtocol. */ @end Now the client code (and I tried EVERY kind of client, signed unsigned, daemon, UI, root privileged, or user-scoped - whatever). For example, in the AppDelegate of a UI app: #import "AppDelegate.h" #import "MYXPCProtocol.h" @interface AppDelegate () @property (strong) IBOutlet NSWindow *window; @property (nonatomic, strong, readwrite) NSXPCConnection *connection; /* lazy initialized */ @end @implementation AppDelegate (NSXPCConnection *) connection {     if (_connection == nil) {         _connection = [[NSXPCConnection alloc] initWithMachServiceName:daemonLabel options:NSXPCConnectionPrivileged];         _connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MYXPCProtocol)];         _connection.invalidationHandler =  ^{             self->_connection = nil;             NSLog(@"connection has been invalidated");         };         [_connection resume];         /* New connections always start suspended */     }     return _connection; } (IBAction) getServiceStatus:(id)sender {     [self.connection.remoteObjectProxy getStatus:^(NSString * _Nonnull status) {         NSLog(@"MY XPC Service status is: %@", status);     }]; } @end but no matter what I do - I always get the "connection invalidated". The sample launchDaemon that works - is not code-signed at all!!! but mine, which is both signed and checking of which yields $ spctl --assess --verbose IMyDaemonApp.app IMyDaemonApp.app: accepted source=Notarized Developer ID   I'm at a loss - and would like to get any advice, or any helpful documentation (I've been reading TN2083, and man launchctl and man launchd.plist and many other pages - to no avail. There seems to be no real "programming guide" for XPC and no reasonable sample code on Apple developer site to fit my needs. Last - this is MacOS 10.15.7, and latest Xcode 12.3
7
0
3.0k
Oct ’22
Allowing dynamic name registration in xpc_connection_create_mach_service
In the "Mach Services" section of the xpc_connection_create(3) man page, we have the following: Important: New service names may NOT be dynamically registered using xpc_connection_create_mach_service(). Only launchd jobs may listen on certain service names, and any service name that the job wishes to listen on must be declared in its launchd.plist(5). XPC may make allowances for dynamic name registration in debug scenarios, but these allowances abso- lutely will NOT be made in the production scenario. In a debugging scenario, how can I allow a dynamic name resolution for listeners? While the man page references this, it doesn't detail how to, and I can't find any information online about this. I can't tell if this text implies that it's currently possible, or may be allowed sometime in the future.
5
0
1.7k
Oct ’22
Get token audit for a NSXPCConnection
Hi, I have a question regarding securing XPC communication. I'm trying to get on the server side the process audit token for the connecting client. I've saw NSXPCConnection has a member called auditSessionIdentifier which I saw it is always returning same number for different connections. What does this represent, can it be used to identify the client connecting process? NSXPCConnection has auditToken, which is what I need, but it is a private property. I would use this, but I'm not sure if this will not result in app being rejected by Apple. Is anyone using it and had the app rejected/accepted? NSXPCConnection has processIdentifier but this alone it is kind of useless. But I was thinking to combine this with task_extmod_info (detect process changes) and audit token with task_name_for_pid. Any other suggestions to get the client process audit token based on NSXPCConnection? Thanks
5
0
3.0k
Oct ’22
Intermittently browser is getting disconnected with NetworkExtension
Hi, Greetings for the day! We would like to update you that we have created Content Filter NetworkExtension and this extension is working fine till Big Sur M1 however we are facing some strange problem in M1 Monterey. Intermittently, When we try to browse websites, it does not respond and after 3-5 minutes its opened the websites correctly. We would like to update you that our subclass overrides handleNewFlow, handleInboundDataFromFlow, handleOutboundDataFromFlow, handleInboundDataCompleteForFlow and handleOutboundDataCompleteForFlow. In all these methods we first check whether NEFilterFlow is nil or not and then pauseVerdict and once asynchronous methods completes execution then we call resumeFlow with verdict (allowVerdict/dropVerdict). When above mentioned issue generated we collected console streaming log and found these lines in the logs (Not from our application): Ignoring resume command for flow 3c8faf3c4a9f7 which does not exist Ignoring resume command for flow 3c90795d4d6f9 which does not exist Ignoring resume command for flow 3c9086d1ede69 which does not exist Ignoring resume command for flow 3c909b251d53b which does not exist We are not sure how above line get printed because we don’t have this logs in our source code so we would need your help to understand this problem and resolution so that we can solve this issue. We have couple of extra queries: What is flow mentioned in above logs in bold text? Is it NEFilterFlow's identifier or something else? How we can validate whether NEFilterFlow is valid or not before calling resumeFlow Why above line is getting printed in log which says flow does not exist. Is there any timeout maintained by NetworkExtension? We are using XPC for interprocess communication so our question is that, Is NetworkExtension/XPC maintain the queue size and if it overflow the size then above line is getting printed. If this is the case then how we can handle that? Is it known issue in NetworkExtension framework itself on M1 Monterey? Thanks & Regards, Mohmad Vasim
13
0
2.8k
Sep ’22
What is a Mach Service?
I've seen the term "Mach Service" used in many places. One such place being the man page for launchd.plist, another being xpc_connection_create_mach_service, yet I cannot find any documentation online explicitly defining what a Mach Service is. Closest thing I've found is the Mach Overview documentation, but that seems to be unrelated to "Mach Services" and closer to a more abstract umbrella term for a list of kernel primitives. So what is a Mach Service and what is the Mach bootstrap namespace? What functionality is it capable of? What is its purpose within an Application Bundle?
2
0
3.5k
Sep ’22
HmCharacteristic.readValue always crashes with bundleID is invalid and XPC not entitled
I want to print out every hmCharacteristic's value in my Smart Home and therefore created this screen (code see below). Unfortunately, I am always getting these two errors whenever I try to call the HmCharacteristic.readValue() function (error messages see below). I am using a physical test iPhone with a real HomeKit Smart Home (no HomeKitAccessorySimulator). I am also using a paid apple developer Account and did enable the HomeKit entitlement as well as allowed the app to use HomeKit data on my test iPhone. My question is: Why do I get the bundleId is invalid and XPC not entitled errors and how do I fix them? import SwiftUI import HomeKit struct screen: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundColor(.accentColor) Text("Hello, world!") } .padding() } init() { let hmHomeManager = HMHomeManager(); DispatchQueue.main.asyncAfter(deadline: .now() + 1) { for hmHome in hmHomeManager.homes { for hmRoom in hmHome.rooms { for hmAccessory in hmRoom.accessories { for hmService in hmAccessory.services { for hmCharacteristic in hmService.characteristics { Task { hmCharacteristic.readValue { error in print("\(hmHome.name)/\(hmRoom.name)/\(hmAccessory.name)/\(hmService.name)/\(hmCharacteristic.localizedDescription) = \(hmCharacteristic.value ?? "[[nil]]")") } } } } } } } }; } } struct ContentView_Previews: PreviewProvider { static var previews: some View { screen() } } validateSessionInfo: bundleID is invalid. Please specify the bundleID for kRTCReportingSessionInfoClientBundleID initWithSessionInfo: XPC not entitled, 1
0
0
793
Sep ’22
[iOS 16 Crash] Crash while getting mach port from CFMessagePortRef
I create a local CFMessagePortRef using CFMessagePortCreateLocal and then use CFMachPortGetPort() to try to get the mach port from it like below: NSString *portIdentifier = [[groupName stringByAppendingString:@"."] stringByAppendingString:sdkId]; NSString *portName = [[portIdentifier stringByAppendingString:@"."] stringByAppendingString:@"mach.port"]; CFMessagePortContext context = {0,(__bridge void *)self,nil,nil,nil}; self.sendPort = CFMessagePortCreateLocal(kCFAllocatorDefault, (__bridge CFStringRef)portName, &callback, &context, false); CFMachPortGetPort(ms->_port); It works till iOS 15 but crashes on iOS 16. Can anyone help? I have defined below definition of __CFMessagePort: struct __CFMessagePort {     CFRuntimeBase _base;     CFLock_t _lock;     CFStringRef _name;     CFMachPortRef _port;        /* immutable; invalidated */     CFMutableDictionaryRef _replies;     int32_t _convCounter;     int32_t _perPID;            /* zero if not per-pid, else pid */     CFMachPortRef _replyPort;        /* only used by remote port; immutable once created; invalidated */     CFRunLoopSourceRef _source;        /* only used by local port; immutable once created; invalidated */     dispatch_source_t _dispatchSource;  /* only used by local port; invalidated */     dispatch_queue_t _dispatchQ;    /* only used by local port */     CFMessagePortInvalidationCallBack _icallout;     CFMessagePortCallBack _callout;    /* only used by local port; immutable */     CFMessagePortCallBackEx _calloutEx;    /* only used by local port; immutable */     CFMessagePortContext _context;    /* not part of remote port; immutable; invalidated */ };
4
0
2.1k
Sep ’22
XPC and App-to-App Communication
I’ve explained this issue many times before, both here on DevForums and in DTS tech support incidents, but never in a coherent fashion. This week I received yet another DTS TSI about this issue, and I’m using that as an excuse to write it up properly (-: Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" XPC and App-to-App Communication There is no supported way to directly communicate between apps using XPC. In the beginning… … there was Mach messaging. In Mach messaging, services are represented by a port, a kernel object that manages message-based IPC. A server has a receive right for a port, allowing it to receive messages that were sent to that port. A client that wants to send a message to a port must have a send right for that port. Mach is a capability-based system. You can’t create a send right from scratch; you must be granted it by someone. Mach messages can transfer send rights from process to process. However, this presents a chicken and egg problem: How do you get your first send right? The answer here is the bootstrap service. Every process starts with a send right to a bootstrap port. When a process wants to access a service, it sends a message with the service name to the bootstrap port. On success, the bootstrap service replies with a message with a send right to the port for that service. Not all processes talk to the same bootstrap port. Rather, the system manages multiple bootstrap ports, where each port represents a bootstrap namespace. The system gives each process a send right to the bootstrap port that’s appropriate for its execution context. The bootstrap service uses this bootstrap port to determine what service names are accessible to a client talking to that port. These bootstrap namespaces form a tree. At the root there is a global bootstrap namespace. A launchd daemon runs in that namespace. Below that are a set of per-user bootstrap namespaces, and below those are per-session bootstrap namespaces for each login sessions. A GUI app runs in a login session namespace. For a more in-depth explanation of this concept, see the Execution Contexts section of Technote 2083 Daemons and Agents. IMPORTANT That technote is very old and the bootstrap namespace model is now significantly more complex than what’s described there. However, the basic ideas are still valid. XPC Fundamentals XPC wraps Mach messaging in an API that’s much easier to use. An XPC connection represents a communication channel between two processes. An XPC listener listens for incoming connections. While there are anonymous listeners, most listeners are associated with a named endpoint, where the name is registered in a bootstrap namespace. This is what allows the client to connect to the listener by name. XPC is tightly integrated with the on-demand architecture supported by launchd. launchd manages a set of jobs — XPC services, launchd daemons and agents, and so on — and each job publishes a set of named endpoints. Client processes connect to these endpoints by name. Under the covers, XPC looks up the name in the client’s bootstrap namespace. A launchd job doesn’t need to run to publish its named endpoints. Rather, launchd learns about the endpoints by reading a property list associated with the job. For example: An XPC service advertises a single named endpoint, namely the bundle ID in the service’s Info.plist; for the details, see the xpcservice.plist man page. A launchd daemon can advertise multiple named endpoints via the MachServices property in its launchd property list; for the details, see the launchd.plist man page. launchd monitors these named endpoints for demand. When a client process sends a message to a connection that targets a named endpoint, launchd starts the associated job. The job then services the demand by starting XPC listeners for its named endpoints. XPC has two APIs: The low-level C API The Foundation XPC API, commonly referred to by the main class name, NSXPCConnection This post focuses on the latter but the same concepts apply to both. App-to-App Problems The XPC architecture is incompatible with direct app-to-app communication: There’s no way for launchd to know what named endpoints it should monitor on your app’s behalf. Launching an app is a heavyweight operation, one clearly visible to the user, so it’s not something that launchd can do on demand. This limitation is reflected in the XPC API. Specifically, there are three ways to create an XPC listener: The service() class method — This creates a listener for an XPC service’s named endpoint. The init(machServiceName:) initialiser — This creates a listener for one of the names advertised in the MachServices property of a launchd daemon or agent. The anonymous() class method — This creates an anonymous listener. None of these are useful in setting up app-to-app communication. The Xcode Gotcha One particularly gnarly gotcha here is that app-to-app communication using XPC works when you run your apps from Xcode. This is a side effect of the infrastructure used by Xcode to debug XPC services. That infrastructure allows the listener app to create a listener using init(machServiceName:) even though the corresponding service name is not known to launchd. So your code works in the debugger but then fails when you run it from the Finder. Ouch! Alternatives If you can’t use XPC for app-to-app communication, what are the alternatives? Here’s a short list of things that might work: Unix domain sockets — For the details, see the unix man page, or any good text book an BSD Sockets. CFMessagePort — For the details, see its documentation. XPC rendezvous — See the XPC Rendezvous section, below. Which is best depends on your circumstances. Unix domain sockets is an industry standard API that works well. It relies on the BSD Sockets API, which is un-fun to call from Swift. Its access control is based on file system permissions, which is helpful if you need to cut across bootstrap namespaces. In contrast, CFMessagePort is a thin wrapper around Mach messaging. That means that its tied to your bootstrap namespace, which can be useful. It’s relatively easy to call from Swift, but still not trivial. XPC rendezvous is based on XPC, so it has all of its advantages. The main disadvantages is that it requires a launchd job to help with the rendezvous, which isn’t always feasible. Oh, and here’s a short list of things to avoid: Mach messaging — I strongly recommend against using Mach messaging directly. It’s almost impossible to use correctly. Distributed Objects (DO) — This has been deprecated for many years now, and for good reason. It has a wide range of weird and wonderful bugs. XPC Rendezvous One way to set up app-to-app communication is with an XPC rendezvous. This technique requires a launchd job that’s visible to both parties: This launchd job advertises a named endpoint. Client A calls the anonymous() class method to create an anonymous listener. It then uses the endpoint property to get an endpoint (NSXPCListenerEndpoint) for that listener. It uses XPC to send this endpoint to the launchd job. The launchd job stores this endpoint. Client B uses XPC to get the endpoint from the launchd job. Client B passes the endpoint to the init(listenerEndpoint:) initialiser to open a connection directly to client A. IMPORTANT The launchd job in step one cannot be an XPC service. Third-party XPC services are always scoped to their container app (see the discussion of the ServiceType property in the xpcservice.plist man page) and thus can’t fulfil the primary requirement of an XPC rendezvous, namely, to be visible to both parties. Most other launchd jobs do work for this, including: launchd daemons and agents Service Management login items System extensions
0
0
6k
Sep ’22
XPC execute response block when one side died
Hi, I have a problem with XPC communication, maybe someone has a suggestion how to fix it. So I have 2 applications that communicate over XPC (NSXPCConnection). One app (sender) calls a method that ends up on the other side(receiver). The method has a completion block to get the response back. The problem is that the receiver crashes while executing the method, before sending back a response. The invalidationHandler is called, because the connection died. My question is: is there a way to make XPC execute the response block, with error or something? If not, any suggestions how to handle this case, to "fake" call the response block for sender? Thanks
3
0
1.7k
Sep ’22
[XPC] Are there errors that are only reported to a send message replyBlock?
Context The event handler of an xpc_connection_t object named myConnection is set and handles XPC_TYPE_ERROR objects: xpc_connection_set_event_handler(myConnection, ^(xpc_object_t object) { }); A message is sent using: xpc_connection_send_message_with_reply(myConnection, myMessage , myQueue, ^(xpc_object_t object) { }); The documentation for the well-known XPC_ERROR_ dictionaries and for xpc_connection_set_event_handler seems to suggest that all the errors received via the reply block will also be received by the event handler. Question Are there error cases where only the reply block of xpc_connection_send_message_with_reply will receive an XPC_ERROR*_ object?
Replies
1
Boosts
0
Views
1.5k
Activity
Jan ’23
Troubleshooting the launch of local user XPC Launch Agent
This is a follow up to the thread, Troubleshooting the launch of local user XPC Launch Agent, in the original (and now archived) Dev Forums.Based on further tests, I assume there must be some configuration that I'm not setting up correctly, as opposed to the code.I started from scratch again with a fresh Xcode Project. This time, I based the code mostly on the example code posted by Apple Engineer eskimo1 in this thread (which uses an privileged Launch Daemon) with a modification or two based on the code posted by Apple Engineer dsorresso in this thread. As I assume that their code can be expected to work (i.e.- to help rule out a coding error on my part). Except that I modified the code so that it works with/as an XPC Service Launch Agent without the privileged aspect and which resides inside of the user's home directory.The following was all done on OS X 10.10.3 (14D136) Yosemite and built with Xcode 6.3.2 (6D2105).* I first started off both the command line interface program and the XPC Service Launch Agent without Code Signing or Sandboxing. When the command line interface program was run at the command line, I got output such as the following. Which more or less resembles the behaviour I was seeing with my own test code.connection event error Connection invalid* Then I code signed both items. No change in the output.* Next, I Sandboxed both. While there was no change in the output at the command line, some entries containing 'deny mach-lookup' began to appear in the System Console logs -&gt; in asl -&gt; with the AUX prefix. e.g.CLIHelloToLaunch(6103) deny mach-lookup com.test.XPCLA* Later, I added a com.apple.security.temporary-exception.mach-lookup.global-name key of Type Array containing the Bundle Identifier of the XPC Service Launch Agent in the Entitlements files for both Targets. No change in the command line output and 'deny mach-lookup' entries still appeared in System Console logs -&gt; asl -&gt; AUX.* As well, I also added an App Group to the Entitlements files for both Targets. No change in the command line output and 'deny mach-lookup' entries still appeared in System Console logs -&gt; asl -&gt; AUX.What could be the cause of the XPC connection errors? I presume that the 'deny mach-lookup' entries are related. How can I fix this?This is the contents of the launchd plist file for the XPC Service Launch Agent. It resides in ~/Library/LaunchAgents:&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt; &lt;plist version="1.0"&gt; &lt;dict&gt; &lt;key&gt;Label&lt;/key&gt; &lt;string&gt;com.test.XPCLA&lt;/string&gt; &lt;key&gt;MachService&lt;/key&gt; &lt;dict&gt; &lt;key&gt;com.test.XPCLA&lt;/key&gt; &lt;true/&gt; &lt;/dict&gt; &lt;key&gt;ProgramArguments&lt;/key&gt; &lt;array&gt; &lt;string&gt;~/Library/Application Support/com.test.XPCLA.xpc&lt;/string&gt; &lt;/array&gt; &lt;/dict&gt; &lt;/plist&gt;This is the code being used in the XPC Service Launch Agent. Specifically, in it's main.m file. After building, I put the .xpc Launch Agent in ~/Library/Application Support for testing.#import &lt;Foundation/Foundation.h&gt; #include &lt;xpc/xpc.h&gt; static void SetupConnection(xpc_connection_t connection) { xpc_connection_set_event_handler(connection, ^(xpc_object_t object) { if ( xpc_get_type(object) == XPC_TYPE_ERROR ) { fprintf(stderr, "connection error %s\n", xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION)); xpc_connection_cancel(connection); } else if ( xpc_get_type(object) == XPC_TYPE_DICTIONARY ) { const char * name; fprintf(stderr, "connection message\n"); name = xpc_dictionary_get_string(object, "name"); if (name == NULL) { fprintf(stderr, "no name\n"); xpc_connection_cancel(connection); } else { xpc_object_t response; char * responseStr; fprintf(stderr, "name is '%s'\n", name); (void) asprintf(&amp;responseStr, "hello %s", name); response = xpc_dictionary_create(NULL, NULL, 0); assert(response != NULL); xpc_dictionary_set_string(response, "greeting", responseStr); xpc_connection_send_message(connection, response); // xpc_release(response); } } else { assert(false); } }); xpc_connection_resume(connection); } int main(int argc, char** argv) { xpc_connection_t listener; fprintf(stderr, "XPC Helper start\n"); listener = xpc_connection_create_mach_service("com.test.XPCLA", NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); assert(listener != NULL); xpc_connection_set_event_handler(listener, ^(xpc_object_t object) { if ( xpc_get_type(object) == XPC_TYPE_ERROR ) { fprintf(stderr, "listener error\n"); // XPC_ERROR_KEY_DESCRIPTION } else if ( xpc_get_type(object) == XPC_TYPE_CONNECTION ) { fprintf(stderr, "listener connection\n"); SetupConnection(object); } else { assert(false); } }); xpc_connection_resume(listener); dispatch_main(); return EXIT_SUCCESS; }This is the code in the command line interface program's main.m file. After building, I put the program into ~/Applications.#import &lt;Foundation/Foundation.h&gt; #include &lt;xpc/xpc.h&gt; static BOOL Test(void) { BOOL success; xpc_connection_t connection; xpc_object_t request; xpc_object_t response; response = NULL; connection = xpc_connection_create_mach_service("com.test.XPCLA", NULL, 0); assert(connection != NULL); request = xpc_dictionary_create(NULL, NULL, 0); assert(request != NULL); xpc_dictionary_set_string(request, "name", "Hello service, this is the program speaking, are you out there?"); xpc_connection_set_event_handler(connection, ^(xpc_object_t object) { fprintf(stderr, "connection event\n"); if ( xpc_get_type(object) == XPC_TYPE_ERROR ) { fprintf(stderr, "error %s\n", xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION)); } else if ( xpc_get_type(object) == XPC_TYPE_DICTIONARY ) { const char * greeting; fprintf(stderr, "response\n"); greeting = xpc_dictionary_get_string(object, "greeting"); fprintf(stderr, "greeting is '%s'\n", greeting); } else { fprintf(stderr, "something else\n"); } }); xpc_connection_resume(connection); xpc_connection_send_message(connection, request); dispatch_main(); if (request != NULL) { xpc_release(request); } if (response != NULL) { xpc_release(response); } return success; } int main(int argc, const char * argv[]) { @autoreleasepool { NSLog(@"%@", @"About to run test of XPC Service."); Test(); } return 0; }Here are the command line program's Entitlements.&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt; &lt;plist version="1.0"&gt; &lt;dict&gt; &lt;key&gt;com.apple.security.app-sandbox&lt;/key&gt; &lt;true/&gt; &lt;key&gt;com.apple.security.temporary-exception.mach-lookup.global-name &lt;/key&gt; &lt;array&gt; &lt;string&gt;com.test.XPCLA&lt;/string&gt; &lt;/array&gt; &lt;key&gt;com.apple.security.application-groups&lt;/key&gt; &lt;array&gt; &lt;string&gt;$(TeamIdentifierPrefix)IPC&lt;/string&gt; &lt;/array&gt; &lt;/dict&gt; &lt;/plist&gt;The XPC Service Launch Agent's Entitlements.&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt; &lt;plist version="1.0"&gt; &lt;dict&gt; &lt;key&gt;com.apple.security.app-sandbox&lt;/key&gt; &lt;true/&gt; &lt;key&gt;com.apple.security.application-groups&lt;/key&gt; &lt;array&gt; &lt;string&gt;$(TeamIdentifierPrefix)IPC&lt;/string&gt; &lt;/array&gt; &lt;key&gt;com.apple.security.temporary-exception.mach-lookup.global-name &lt;/key&gt; &lt;array&gt; &lt;string&gt;com.test.XPCLA&lt;/string&gt; &lt;/array&gt; &lt;/dict&gt; &lt;/plist&gt;Additional notes, if it's relevant:* The command line interface program has an embedded info.plist since it's a single file executable.* Command line interface program was created via Xcode 6.3.2's New Target -&gt; Command Line Tool template* XPC Service was created via Xcode 6.3.2's New Target -&gt; XPC Service template.
Replies
10
Boosts
0
Views
8.6k
Activity
Jan ’23
XPC and ARC?
xctrace --template Leaks identified this as a leak:         NSString *uuid = [NSString stringWithUTF8String:connectionID];         NSData *contentData = [NSData dataWithBytes:data length:length];         id<ConnexctionProtocol> proxy = [connection asyncConnectionProxy];         [proxy handleData:uuid data:contentData]; return; (Which is to say: a few thousand objects show up in the Leaks pane, the stack for them goes up to the NSData creation, and Leaks apparently thinks it's never released.) That doesn't look like it should be a leak, with ARC? Which probably means I'm doing something wrong?
Replies
0
Boosts
0
Views
722
Activity
Dec ’22
NSXPCConnection Data Communication Security
I have two processes that talk to each other using an NSXPCConnection. If I want to pass sensitive data over the connection, should I be worried about it being intercepted or read by other processes? Should I encrypt any sensitive data before sending it over the connection and have the other process have to decrypt it?
Replies
6
Boosts
0
Views
2k
Activity
Dec ’22
Need help resolving a nasty crash
Two Obj-C processes A and B, communicating via XPC, using NSXPCConnection (the connection is created from an endpoint, unnamed). The method signature is this: - (void)userAction:(NSString *)identifier             update:(OITNFWPreventionStage)stage          eventInfo:(NSDictionary * _Nonnull)actionInfo          withError:(NSError * _Nullable)error              reply:(void (^ _Nullable)(BOOL))reply; I'm using a normal asynchronous proxy id<myProtocol> monitorProxy = [self.monitorConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {         NSLog( @"Monitoring XPC proxy call failed: %@", error);     }]; Since the actionInfo I'm using is NSMutableDictionary the gets updated frequently from concurrent queues and thread - I synchronize ALL my calls from process A to process B on an NSOperationQueue     NSOperationQueue *monitorUpdateQueue = [[NSOperationQueue alloc] init];     monitorUpdateQueue.name = @"monitoring queue";     monitorUpdateQueue.maxConcurrentOperationCount = 1;     monitorUpdateQueue.qualityOfService = NSQualityOfServiceUtility; My calls typically look like this:     [monitorUpdateQueue addOperationWithBlock:^{         actionInfo[@"Files"] = [fileEvents valueForKeyPath:@"dictionary"]; // some NSArray of NSDictionaries         actionInfo[@"stage"] = ActionStagePreblocked;         [monitorProxy userAction:userActionIdentifier update:ActionStagePreblocked eventInfo:actionInfo withError:nil reply:^(BOOL reported) {             NSLog(@"Action reported");         }];     }]; Now every now and then, Process A (the caller) crashes inside this remote call... I Full crash log. Couldn't attach .ips file Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: KERN_INVALID_ADDRESS at 0x00004c52f8b94400 Exception Codes: 0x0000000000000001, 0x00004c52f8b94400 Exception Note: EXC_CORPSE_NOTIFY Termination Reason: Namespace SIGNAL, Code 11 Segmentation fault: 11 Terminating Process: exc handler [83282] VM Region Info: 0x4c52f8b94400 is not in any region. Bytes after previous region: 83438207583233 Bytes before following region: 21633872346112 REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL commpage (reserved) 1000000000-7000000000 [384.0G] ---/--- SM=NUL ...(unallocated) ---> GAP OF 0x5f9000000000 BYTES MALLOC_NANO 600000000000-600008000000 [128.0M] rw-/rwx SM=PRV and the thread's stack looks like this: Thread 10 Crashed:: Dispatch queue: monitoring queue (QOS: UTILITY) 0 libobjc.A.dylib 0x18a7e8310 objc_retain + 16 1 Foundation 0x18b8eb4a8 -[NSDictionary(NSDictionary) encodeWithCoder:] + 596 2 Foundation 0x18b8ba5f4 -[NSXPCEncoder _encodeObject:] + 520 3 Foundation 0x18b8b9ae4 _NSXPCSerializationAddInvocationArgumentsArray + 276 4 Foundation 0x18b8b95fc -[NSXPCEncoder _encodeInvocation:isReply:into:] + 256 5 Foundation 0x18b8b8798 -[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:] + 1356 6 CoreFoundation 0x18aa08040 ___forwarding___ + 1088 7 CoreFoundation 0x18aa07b40 _CF_forwarding_prep_0 + 96 8 myproc 0x10041370c __84-[myproc scanContentOfFilesInEvents:userActionInfo:monitorProxy:monitoringQueue:]_block_invoke_2.1588 + 1064 (myproc.m:3690) 9 Foundation 0x18b8e0600 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 24 10 Foundation 0x18b8e04a8 -[NSBlockOperation main] + 104 11 Foundation 0x18b8e0438 __NSOPERATION_IS_INVOKING_MAIN__ + 24 12 Foundation 0x18b8df67c -[NSOperation start] + 804 13 Foundation 0x18b8df350 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 24 14 Foundation 0x18b8df204 __NSOQSchedule_f + 184 15 libdispatch.dylib 0x18a7ad990 _dispatch_block_async_invoke2 + 148 16 libdispatch.dylib 0x18a79ebac _dispatch_client_callout + 20 17 libdispatch.dylib 0x18a7a2080 _dispatch_continuation_pop + 504 18 libdispatch.dylib 0x18a7a16dc _dispatch_async_redirect_invoke + 596 19 libdispatch.dylib 0x18a7b031c _dispatch_root_queue_drain + 396 20 libdispatch.dylib 0x18a7b0b58 _dispatch_worker_thread2 + 164 21 libsystem_pthread.dylib 0x18a959574 _pthread_wqthread + 228 22 libsystem_pthread.dylib 0x18a9582c4 start_wqthread + 8 Sorry for the terrible formatting, I could not attach the .ips file, but I attached its full text. My question: When I'm passing an NSMutableDictionary to the remote proxy. Is it received "mutable" on the other side? and while it is being worked in on the receiving side, what happens if I modify it on the calling side (process A) ? How do Mutable objects behave on XPC calls? The Dictionary I'm moving only contains basic "plist approved" entries - NSString, NSNumber, NSDate, and collections (NSArray, NSDictionary). That's all. No custom classes there. I will be most grateful for any idea or hint.
Replies
3
Boosts
0
Views
3.7k
Activity
Dec ’22
Notification on NSUserDefaults Change When App Is In Background
I have two applications that share an app group @"group.edu.tds.poc.shared"Using NSUserDefaults of this app group, I am able to exchange data between the reader app and the writer app.The Writer App writes data to the NSUserDefaultNSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.edu.tds.poc.shared"]; [share dDefaults setObject:stringToStore forKey:key]; [sharedDefaults synchronize];The Reader App reads the data from the NSUserDefaultNSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.edu.tds.poc.shared"]; return [sharedDefaults stringForKey:@"key"];I now want the reader app to be notified as soon as the writer app modifies the value for the key. I.e. Can I notify the reader app when the writer app is running in the foreground (Reader app is either running in the background or is not running).I have implemented the marked solution but with no luck:Cocoa - Notification on NSUserDefaults value change?NSUserDefaults and KVO issuesCall back only when the Reader App is in foreground state. (Wrote to the Shared Defaults using Reader app)Any idea if this can be achieved?
Replies
6
Boosts
1
Views
3.1k
Activity
Nov ’22
Communicating between System Extension (specifically, camera extension) and Container App
i am trying to send data from the container app to its system extension (specifically, a camera extension. i am not entirely sure how to go about this. i read that i could utilize XPC, and i have tried this but for some reason, the system extension returns nothing when trying to connect to the XPC Service. below is an example code snipper let connectionToService = NSXPCConnection(serviceName: "example.VirtualCameraXPC")     connectionToService.remoteObjectInterface = NSXPCInterface(with:VirtualCameraXPCProtocol.self)     connectionToService.resume() //checking processes available shows that the XPC Server process is never activated also. if let proxy = connectionToService.remoteObjectProxy as? VirtualCameraXPCProtocol {       proxy.getNewString() { aString in //this is never logged.         NSLog("Second result string was: \(aString)")       }     } when i run the above code from the container app, it works properly but from the system extension, i run into the problems commented above in the code block. i would appreciate any help that will help me successfully send data from my container app to my camera extension.
Replies
1
Boosts
0
Views
1.3k
Activity
Nov ’22
Communication between system extension and the app
I have a working NEPacketTunnelProvider app extension macOS app on the App Store. The company wants to explore the possibility of switching to system extension, so that we can distribute the app outside of the appstore too. I managed to do the switch and the extension works. But the communication is broken. DistributedNotificationCenter stopped working for me after switching to system extension, events are not received and I don't see any errors so I cannot say what's wrong. I tried to adopt XPC from this Filtering Network Traffic Apple's sample, but I get sandbox error - domain code 4099, failed at lookup with error 159 - Sandbox restriction. I get the same error if I try to run the sample with my company team id. I do these changes: NEMachServiceName to $(TeamIdentifierPrefix)com.mycompanyname.macos.dev App Groups to $(TeamIdentifierPrefix)com.mycompanyname.macos.dev Bundle ids to com.mycompanyname.macos.dev and com.mycompanyname.macos.dev.tunnelprovider com.mycompanyname.macos.dev has capabilities - App Groups, Network Extensions, System Extensions com.mycompanyname.macos.dev.tunnelprovider - Network Extensions, System Extensions Could you help me find the reason why DistributedNotificationCenter could stop receiving notifications? Or are you able to run Apple's sample? What changes do you make to run it under your team? Because it looks like my changes are wrong Either DistributedNotificationCenter or XPC would solve my problem
Replies
3
Boosts
1
Views
1.5k
Activity
Nov ’22
XPC Connection Not Invalidated on NSXPCListenerDelegate Denial
I am attempting to understand the expected behavior of several points related to XPC. Mainly, I have the following questions: Should I expect that NSXPCConnection.remoteObjectProxyWithErrorHandler to call the error handler if the associated NSXPCListenerDelegate returns false in its listener function? Does the error handler get called immediately if the remoteObjectProxyWithErrorHandler function fails? What does remoteObjectProxy return if an actual proxy object is never exported on the service-side (in the listener function)? Should I expect that NSXPCConnection.invalidate() and/or the connection's invalidationHandler to be called when the associated NSXPCListenerDelegate returns false in its listener function? According to the listener documentation below, it appears the listener function is supposed to invalidate the connection; however, I am not seeing this be the case. https://developer.apple.com/documentation/foundation/nsxpclistenerdelegate/1410381-listener To reject the connect, return a value of false. This causes the connection object to be invalidated. I have written a test that exhibits the fact when the listener function returns false, rather than the invalidationHandler being called, the interruptionHandler is called. import XCTest final class InvalidateTest: XCTestCase {   func testConnectionIsInvalidatedOnListenerRejection() {     //set up anonymous XPC Listener     let listener = NSXPCListener.anonymous()     let listenerDelegate = MockListenerDelegate()     listener.delegate = listenerDelegate     listener.resume()           //establish connection to service     let clientConnection = MockConnection(listenerEndpoint: listener.endpoint)     var interruptHandlerCalled = false     var invalidateHandlerCalled = false     let interruptionHandler = { interruptHandlerCalled = true }     let invalidationHandler = { invalidateHandlerCalled = true }     clientConnection.interruptionHandler = interruptionHandler     clientConnection.invalidationHandler = invalidationHandler     clientConnection.remoteObjectInterface = NSXPCInterface(with: XPCServDelegate.self)     clientConnection.exportedInterface = NSXPCInterface(with: XPCCliDelegate.self)     clientConnection.exportedObject = XPCCDelegate()     clientConnection.resume()           // get the proxy delegate to make the XPC pulse call     guard let proxy = clientConnection.remoteObjectProxy() as? XPCServDelegate else {       XCTAssert(false, "Unable to get proxy object")       return     }     // why is it not failing to get a proxy object in this case?           // make the pulse call     var replyCalled = false     let semaphore = DispatchSemaphore(value: 0)     proxy.pulse(reply: {       replyCalled = true       semaphore.signal()     })           let waitResult = semaphore.wait(timeout: .now() + 1)     XCTAssertEqual(waitResult, .timedOut)     XCTAssertFalse(replyCalled)           // why do these assertions fail?     XCTAssertTrue(clientConnection.invalidateCalled)     XCTAssertTrue(invalidateHandlerCalled)     XCTAssertFalse(interruptHandlerCalled)   } } @objc public protocol XPCServDelegate {   func pulse(reply: @escaping () -> Void) } class XPCSDelegate : XPCServDelegate {   func pulse(reply: @escaping () -> Void) {     reply()   } } @objc public protocol XPCCliDelegate {} class XPCCDelegate : XPCCliDelegate {} fileprivate class MockConnection : NSXPCConnection {   var invalidateCalled = false       override func invalidate() {     invalidateCalled = true     super.invalidate()   } } fileprivate class MockListenerDelegate : NSObject, NSXPCListenerDelegate {   func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {     return false   } }
Replies
0
Boosts
0
Views
1.8k
Activity
Nov ’22
XPC between Container App and System Extension
I'm trying to create an XPC service to communicate between my Endpoint Security Extension and its Container App. I've taken the Sample Endpoint App from here. I've then followed the steps under Creating the Service here In fact, when I added the XPC service via the template, Xcode automatically added an Embed XPC Services phase to the container app. I can confirm that in the built container app I see the xpc service: SampleEndpointApp.app/Contents/XPCServices/Service.xpc If I initiate an NSXPCConnection from the container app then I can both connect and make RPCs. Furthermore I see the service process running via ps and also launchtl. If however I try to initiate an NSXPCConnection from the extension then I see nothing. RPC doesn't work and I don't see the service being launched. I've tried this with and without the connection in the main app. What am I missing here? What needs to be done to allow both processes to talk to each other? Is there some permissions issue here? Note that my plist for the service is as follows:
Replies
13
Boosts
0
Views
3.8k
Activity
Oct ’22
How to publish an XPC Service in a global daemon that employs EndpointSecurity framework?
I have a global daemon managed by launchd, whose .plist is installed in /Library/LaunchDaemons). To be correctly entitled and code-signed so it can communicate with EndpointSecurity framework, its executable resides in a normal Mac App bundle (main() will run as minimal UI when launched from UI, and as a daemon when launched by launchd). This means that the ProgramArguments.0 in its .plist looks something like /Library/PrivilegedHelperTools/MyDaemonApp.app/Contents/MacOS/MyDaemonApp Now I need this daemon to publish an XPC Service (with few control commands) so that other components of our system (UI app, a user-context launchd-daemon and another launchd global-daemon) will be able to connect to The XPC Service and control it via the published protocol. I read some answers here, and also found a working order sample code that does just this here - https://github.com/jdspoone/SampleOSXLaunchDaemon But when I apply its content to my global daemon, word for word - it doesn't work - meaning, clients cannot create a connection to The XPC Service. The daemon is up and running, and functional. its .plist is quite simple and looks like this: <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.mycompany.itm.service</string> <key>KeepAlive</key> <true/> <key>RunAtLoad</key> <true/> <key>MachServices</key> <dict> <key>com.mycompany.itm.service</key> <true/> </dict> <key>ProgramArguments</key> <array> <string>/Library/PrivilegedHelperTools/IMyDaemonApp.app/Contents/MacOS/MyDaemonApp</string> <string>-monitor</string> <string>-protectDeviceProtocol</string> <string>USB</string> </array> </dict> </plist> It creates and starts an XPC listener in MYXPCListener.h like thus: #import <Foundation/Foundation.h> #import "MYXPCProtocol.h" NS_ASSUME_NONNULL_BEGIN @interface OITPreventionXPCService : NSObject (instancetype) init; (void) start; /* Begin listening for incoming XPC connections */ (void) stop; /* Stop listening for incoming XPC connections */ @end NS_ASSUME_NONNULL_END and the implementation is: /* AppDelegate.m */ @interface MYXPCService () <NSXPCListenerDelegate, OITPreventionXPCProtocol> @property (nonatomic, strong, readwrite) NSXPCListener *listener; @property (nonatomic, readwrite) BOOL started; @end @implementation OITPreventionXPCService (instancetype) init {     if ((self = [super init]) != nil) {         _listener = [[NSXPCListener alloc] initWithMachServiceName:@"com.mycompany.itm.service"];         _listener.delegate = self;         if (_listener == nil) {             os_log_error(myLog, "XPCListener failed to initialize");         }         _started = NO;     }     return self; } (void) start {     assert(_started == NO);     [_listener resume];     os_log_info(myLog, "XPCListener resumed");     _started = YES; } (void) stop {     assert(_started == YES);     [_listener suspend];     os_log_info(myLog, "XPCListener suspended");     _started = NO; } /* NSXPCListenerDelegate implementation */ (BOOL) listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {     os_log_info(myLog, "Prevention XPCListener is bequsted a new connection");     assert(listener == _listener);     assert(newConnection != nil);     newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MYXPCProtocol)];     newConnection.exportedObject = self; &#9;&#9;[newConnection resume];     return YES; } /* Further down this implementation, I have implementations to all the methods in MYXPCProtocol. */ @end Now the client code (and I tried EVERY kind of client, signed unsigned, daemon, UI, root privileged, or user-scoped - whatever). For example, in the AppDelegate of a UI app: #import "AppDelegate.h" #import "MYXPCProtocol.h" @interface AppDelegate () @property (strong) IBOutlet NSWindow *window; @property (nonatomic, strong, readwrite) NSXPCConnection *connection; /* lazy initialized */ @end @implementation AppDelegate (NSXPCConnection *) connection {     if (_connection == nil) {         _connection = [[NSXPCConnection alloc] initWithMachServiceName:daemonLabel options:NSXPCConnectionPrivileged];         _connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MYXPCProtocol)];         _connection.invalidationHandler =  ^{             self->_connection = nil;             NSLog(@"connection has been invalidated");         };         [_connection resume];         /* New connections always start suspended */     }     return _connection; } (IBAction) getServiceStatus:(id)sender {     [self.connection.remoteObjectProxy getStatus:^(NSString * _Nonnull status) {         NSLog(@"MY XPC Service status is: %@", status);     }]; } @end but no matter what I do - I always get the "connection invalidated". The sample launchDaemon that works - is not code-signed at all!!! but mine, which is both signed and checking of which yields $ spctl --assess --verbose IMyDaemonApp.app IMyDaemonApp.app: accepted source=Notarized Developer ID   I'm at a loss - and would like to get any advice, or any helpful documentation (I've been reading TN2083, and man launchctl and man launchd.plist and many other pages - to no avail. There seems to be no real "programming guide" for XPC and no reasonable sample code on Apple developer site to fit my needs. Last - this is MacOS 10.15.7, and latest Xcode 12.3
Replies
7
Boosts
0
Views
3.0k
Activity
Oct ’22
TN3113: Testing and debugging XPC code with an anonymous listener
Use an anonymous XPC listener to simplify your XPC testing and debugging. View Technote TN3113 &amp;gt;
Replies
0
Boosts
0
Views
1.3k
Activity
Oct ’22
Allowing dynamic name registration in xpc_connection_create_mach_service
In the "Mach Services" section of the xpc_connection_create(3) man page, we have the following: Important: New service names may NOT be dynamically registered using xpc_connection_create_mach_service(). Only launchd jobs may listen on certain service names, and any service name that the job wishes to listen on must be declared in its launchd.plist(5). XPC may make allowances for dynamic name registration in debug scenarios, but these allowances abso- lutely will NOT be made in the production scenario. In a debugging scenario, how can I allow a dynamic name resolution for listeners? While the man page references this, it doesn't detail how to, and I can't find any information online about this. I can't tell if this text implies that it's currently possible, or may be allowed sometime in the future.
Replies
5
Boosts
0
Views
1.7k
Activity
Oct ’22
Get token audit for a NSXPCConnection
Hi, I have a question regarding securing XPC communication. I'm trying to get on the server side the process audit token for the connecting client. I've saw NSXPCConnection has a member called auditSessionIdentifier which I saw it is always returning same number for different connections. What does this represent, can it be used to identify the client connecting process? NSXPCConnection has auditToken, which is what I need, but it is a private property. I would use this, but I'm not sure if this will not result in app being rejected by Apple. Is anyone using it and had the app rejected/accepted? NSXPCConnection has processIdentifier but this alone it is kind of useless. But I was thinking to combine this with task_extmod_info (detect process changes) and audit token with task_name_for_pid. Any other suggestions to get the client process audit token based on NSXPCConnection? Thanks
Replies
5
Boosts
0
Views
3.0k
Activity
Oct ’22
Intermittently browser is getting disconnected with NetworkExtension
Hi, Greetings for the day! We would like to update you that we have created Content Filter NetworkExtension and this extension is working fine till Big Sur M1 however we are facing some strange problem in M1 Monterey. Intermittently, When we try to browse websites, it does not respond and after 3-5 minutes its opened the websites correctly. We would like to update you that our subclass overrides handleNewFlow, handleInboundDataFromFlow, handleOutboundDataFromFlow, handleInboundDataCompleteForFlow and handleOutboundDataCompleteForFlow. In all these methods we first check whether NEFilterFlow is nil or not and then pauseVerdict and once asynchronous methods completes execution then we call resumeFlow with verdict (allowVerdict/dropVerdict). When above mentioned issue generated we collected console streaming log and found these lines in the logs (Not from our application): Ignoring resume command for flow 3c8faf3c4a9f7 which does not exist Ignoring resume command for flow 3c90795d4d6f9 which does not exist Ignoring resume command for flow 3c9086d1ede69 which does not exist Ignoring resume command for flow 3c909b251d53b which does not exist We are not sure how above line get printed because we don’t have this logs in our source code so we would need your help to understand this problem and resolution so that we can solve this issue. We have couple of extra queries: What is flow mentioned in above logs in bold text? Is it NEFilterFlow's identifier or something else? How we can validate whether NEFilterFlow is valid or not before calling resumeFlow Why above line is getting printed in log which says flow does not exist. Is there any timeout maintained by NetworkExtension? We are using XPC for interprocess communication so our question is that, Is NetworkExtension/XPC maintain the queue size and if it overflow the size then above line is getting printed. If this is the case then how we can handle that? Is it known issue in NetworkExtension framework itself on M1 Monterey? Thanks & Regards, Mohmad Vasim
Replies
13
Boosts
0
Views
2.8k
Activity
Sep ’22
What is a Mach Service?
I've seen the term "Mach Service" used in many places. One such place being the man page for launchd.plist, another being xpc_connection_create_mach_service, yet I cannot find any documentation online explicitly defining what a Mach Service is. Closest thing I've found is the Mach Overview documentation, but that seems to be unrelated to "Mach Services" and closer to a more abstract umbrella term for a list of kernel primitives. So what is a Mach Service and what is the Mach bootstrap namespace? What functionality is it capable of? What is its purpose within an Application Bundle?
Replies
2
Boosts
0
Views
3.5k
Activity
Sep ’22
HmCharacteristic.readValue always crashes with bundleID is invalid and XPC not entitled
I want to print out every hmCharacteristic's value in my Smart Home and therefore created this screen (code see below). Unfortunately, I am always getting these two errors whenever I try to call the HmCharacteristic.readValue() function (error messages see below). I am using a physical test iPhone with a real HomeKit Smart Home (no HomeKitAccessorySimulator). I am also using a paid apple developer Account and did enable the HomeKit entitlement as well as allowed the app to use HomeKit data on my test iPhone. My question is: Why do I get the bundleId is invalid and XPC not entitled errors and how do I fix them? import SwiftUI import HomeKit struct screen: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundColor(.accentColor) Text("Hello, world!") } .padding() } init() { let hmHomeManager = HMHomeManager(); DispatchQueue.main.asyncAfter(deadline: .now() + 1) { for hmHome in hmHomeManager.homes { for hmRoom in hmHome.rooms { for hmAccessory in hmRoom.accessories { for hmService in hmAccessory.services { for hmCharacteristic in hmService.characteristics { Task { hmCharacteristic.readValue { error in print("\(hmHome.name)/\(hmRoom.name)/\(hmAccessory.name)/\(hmService.name)/\(hmCharacteristic.localizedDescription) = \(hmCharacteristic.value ?? "[[nil]]")") } } } } } } } }; } } struct ContentView_Previews: PreviewProvider { static var previews: some View { screen() } } validateSessionInfo: bundleID is invalid. Please specify the bundleID for kRTCReportingSessionInfoClientBundleID initWithSessionInfo: XPC not entitled, 1
Replies
0
Boosts
0
Views
793
Activity
Sep ’22
[iOS 16 Crash] Crash while getting mach port from CFMessagePortRef
I create a local CFMessagePortRef using CFMessagePortCreateLocal and then use CFMachPortGetPort() to try to get the mach port from it like below: NSString *portIdentifier = [[groupName stringByAppendingString:@"."] stringByAppendingString:sdkId]; NSString *portName = [[portIdentifier stringByAppendingString:@"."] stringByAppendingString:@"mach.port"]; CFMessagePortContext context = {0,(__bridge void *)self,nil,nil,nil}; self.sendPort = CFMessagePortCreateLocal(kCFAllocatorDefault, (__bridge CFStringRef)portName, &callback, &context, false); CFMachPortGetPort(ms->_port); It works till iOS 15 but crashes on iOS 16. Can anyone help? I have defined below definition of __CFMessagePort: struct __CFMessagePort {     CFRuntimeBase _base;     CFLock_t _lock;     CFStringRef _name;     CFMachPortRef _port;        /* immutable; invalidated */     CFMutableDictionaryRef _replies;     int32_t _convCounter;     int32_t _perPID;            /* zero if not per-pid, else pid */     CFMachPortRef _replyPort;        /* only used by remote port; immutable once created; invalidated */     CFRunLoopSourceRef _source;        /* only used by local port; immutable once created; invalidated */     dispatch_source_t _dispatchSource;  /* only used by local port; invalidated */     dispatch_queue_t _dispatchQ;    /* only used by local port */     CFMessagePortInvalidationCallBack _icallout;     CFMessagePortCallBack _callout;    /* only used by local port; immutable */     CFMessagePortCallBackEx _calloutEx;    /* only used by local port; immutable */     CFMessagePortContext _context;    /* not part of remote port; immutable; invalidated */ };
Replies
4
Boosts
0
Views
2.1k
Activity
Sep ’22
XPC and App-to-App Communication
I’ve explained this issue many times before, both here on DevForums and in DTS tech support incidents, but never in a coherent fashion. This week I received yet another DTS TSI about this issue, and I’m using that as an excuse to write it up properly (-: Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" XPC and App-to-App Communication There is no supported way to directly communicate between apps using XPC. In the beginning… … there was Mach messaging. In Mach messaging, services are represented by a port, a kernel object that manages message-based IPC. A server has a receive right for a port, allowing it to receive messages that were sent to that port. A client that wants to send a message to a port must have a send right for that port. Mach is a capability-based system. You can’t create a send right from scratch; you must be granted it by someone. Mach messages can transfer send rights from process to process. However, this presents a chicken and egg problem: How do you get your first send right? The answer here is the bootstrap service. Every process starts with a send right to a bootstrap port. When a process wants to access a service, it sends a message with the service name to the bootstrap port. On success, the bootstrap service replies with a message with a send right to the port for that service. Not all processes talk to the same bootstrap port. Rather, the system manages multiple bootstrap ports, where each port represents a bootstrap namespace. The system gives each process a send right to the bootstrap port that’s appropriate for its execution context. The bootstrap service uses this bootstrap port to determine what service names are accessible to a client talking to that port. These bootstrap namespaces form a tree. At the root there is a global bootstrap namespace. A launchd daemon runs in that namespace. Below that are a set of per-user bootstrap namespaces, and below those are per-session bootstrap namespaces for each login sessions. A GUI app runs in a login session namespace. For a more in-depth explanation of this concept, see the Execution Contexts section of Technote 2083 Daemons and Agents. IMPORTANT That technote is very old and the bootstrap namespace model is now significantly more complex than what’s described there. However, the basic ideas are still valid. XPC Fundamentals XPC wraps Mach messaging in an API that’s much easier to use. An XPC connection represents a communication channel between two processes. An XPC listener listens for incoming connections. While there are anonymous listeners, most listeners are associated with a named endpoint, where the name is registered in a bootstrap namespace. This is what allows the client to connect to the listener by name. XPC is tightly integrated with the on-demand architecture supported by launchd. launchd manages a set of jobs — XPC services, launchd daemons and agents, and so on — and each job publishes a set of named endpoints. Client processes connect to these endpoints by name. Under the covers, XPC looks up the name in the client’s bootstrap namespace. A launchd job doesn’t need to run to publish its named endpoints. Rather, launchd learns about the endpoints by reading a property list associated with the job. For example: An XPC service advertises a single named endpoint, namely the bundle ID in the service’s Info.plist; for the details, see the xpcservice.plist man page. A launchd daemon can advertise multiple named endpoints via the MachServices property in its launchd property list; for the details, see the launchd.plist man page. launchd monitors these named endpoints for demand. When a client process sends a message to a connection that targets a named endpoint, launchd starts the associated job. The job then services the demand by starting XPC listeners for its named endpoints. XPC has two APIs: The low-level C API The Foundation XPC API, commonly referred to by the main class name, NSXPCConnection This post focuses on the latter but the same concepts apply to both. App-to-App Problems The XPC architecture is incompatible with direct app-to-app communication: There’s no way for launchd to know what named endpoints it should monitor on your app’s behalf. Launching an app is a heavyweight operation, one clearly visible to the user, so it’s not something that launchd can do on demand. This limitation is reflected in the XPC API. Specifically, there are three ways to create an XPC listener: The service() class method — This creates a listener for an XPC service’s named endpoint. The init(machServiceName:) initialiser — This creates a listener for one of the names advertised in the MachServices property of a launchd daemon or agent. The anonymous() class method — This creates an anonymous listener. None of these are useful in setting up app-to-app communication. The Xcode Gotcha One particularly gnarly gotcha here is that app-to-app communication using XPC works when you run your apps from Xcode. This is a side effect of the infrastructure used by Xcode to debug XPC services. That infrastructure allows the listener app to create a listener using init(machServiceName:) even though the corresponding service name is not known to launchd. So your code works in the debugger but then fails when you run it from the Finder. Ouch! Alternatives If you can’t use XPC for app-to-app communication, what are the alternatives? Here’s a short list of things that might work: Unix domain sockets — For the details, see the unix man page, or any good text book an BSD Sockets. CFMessagePort — For the details, see its documentation. XPC rendezvous — See the XPC Rendezvous section, below. Which is best depends on your circumstances. Unix domain sockets is an industry standard API that works well. It relies on the BSD Sockets API, which is un-fun to call from Swift. Its access control is based on file system permissions, which is helpful if you need to cut across bootstrap namespaces. In contrast, CFMessagePort is a thin wrapper around Mach messaging. That means that its tied to your bootstrap namespace, which can be useful. It’s relatively easy to call from Swift, but still not trivial. XPC rendezvous is based on XPC, so it has all of its advantages. The main disadvantages is that it requires a launchd job to help with the rendezvous, which isn’t always feasible. Oh, and here’s a short list of things to avoid: Mach messaging — I strongly recommend against using Mach messaging directly. It’s almost impossible to use correctly. Distributed Objects (DO) — This has been deprecated for many years now, and for good reason. It has a wide range of weird and wonderful bugs. XPC Rendezvous One way to set up app-to-app communication is with an XPC rendezvous. This technique requires a launchd job that’s visible to both parties: This launchd job advertises a named endpoint. Client A calls the anonymous() class method to create an anonymous listener. It then uses the endpoint property to get an endpoint (NSXPCListenerEndpoint) for that listener. It uses XPC to send this endpoint to the launchd job. The launchd job stores this endpoint. Client B uses XPC to get the endpoint from the launchd job. Client B passes the endpoint to the init(listenerEndpoint:) initialiser to open a connection directly to client A. IMPORTANT The launchd job in step one cannot be an XPC service. Third-party XPC services are always scoped to their container app (see the discussion of the ServiceType property in the xpcservice.plist man page) and thus can’t fulfil the primary requirement of an XPC rendezvous, namely, to be visible to both parties. Most other launchd jobs do work for this, including: launchd daemons and agents Service Management login items System extensions
Replies
0
Boosts
0
Views
6k
Activity
Sep ’22
XPC execute response block when one side died
Hi, I have a problem with XPC communication, maybe someone has a suggestion how to fix it. So I have 2 applications that communicate over XPC (NSXPCConnection). One app (sender) calls a method that ends up on the other side(receiver). The method has a completion block to get the response back. The problem is that the receiver crashes while executing the method, before sending back a response. The invalidationHandler is called, because the connection died. My question is: is there a way to make XPC execute the response block, with error or something? If not, any suggestions how to handle this case, to "fake" call the response block for sender? Thanks
Replies
3
Boosts
0
Views
1.7k
Activity
Sep ’22