Inter-process communication

RSS for tag

Share data through Handoff, support universal links to your app's content, and display activity-based services to the user using inter-process communication.

Inter-process communication Documentation

Posts under Inter-process communication tag

44 Posts
Sort by:
Post marked as solved
11 Replies
646 Views
I'm writing a Agent Application that records the Screen and I'm trying to keep the recording going even when the user logs out. I've been reading about LaunchAgents and LaunchDaemons. From what I understand a Prelogin LaunchAgent is my best bet since I need NSApplication to keep my process going and to access the screens. I'm only able to relaunch the app after login or to reopen the app when the os closes it. But the recording process is interrupted. Here is what I have as far as my LaunchAgent. My prelogin LaunchAgent (to open the app during the LoginWindow context) <?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.myApp.prelogin</string> <key>LimitLoadToSessionType</key> <string>LoginWindow</string> <key>RunAtLoad</key> </true> <key>ProgramArguments</key> <array> <string>/Library/myApp/myAgent0</string> <string>service</key> <array> <key>QueueDirectories</key> <array> <string>/etc/myApp/service</string> </array> </dict> </plist> Per user launch agent (to keep the application open while a file exists in the path of QueDirectories) <?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.myApp.peruser</string> <key>LimitLoadToSessionType</key> <string>Aqua</string> <key>RunAtLoad</key> <true/> <key>ProgramArguments</key> <array> <string>/Library/myApp/vmyAgent0</string> <string>service</string> </array> <key>QueueDirectories</key> <array> <string>/etc/myApp/service</string> </array> </dict> </plist> And then a daemon that I was suggested to add. <?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.myApp.server</string> <key>ProgramArguments</key> <array> <string>/Library/myApp/myAgent0</string> <string>-service</string> </array> <key>QueueDirectories</key> <array> <string>/etc/myApp/service</string> </array> </dict> </plist> Currently the application get closed down when the user logs out and gets reopened when the user logs back in or every time I close it (until I remove the file from QueueDirectories). I'm not sure if it gets open during LoginWindow but I don't see any recordings of that so I don't think it does. I know it is possible since VNC viewer does it (you can remotely log into your Mac). I'm not even sure I'm on the right track and I found this other question which tells me I'm on the wrong side using NSApplication for something like this? I'm in need of confirmations lol. Thank you in advance.
Posted
by
Post not yet marked as solved
4 Replies
526 Views
Background Alright, so there's a lot of voodoo and undocumented stuff going on here but hopefully somebody can help me out. I've reverse engineered how stuff might work based on: https://opensource.apple.com/source/launchd/launchd-442.21/support/launchctl.c.auto.html https://developer.apple.com/library/archive/technotes/tn2083/_index.html#//apple_ref/doc/uid/DTS10003794-CH1-SUBSECTION10 I've got a launchdaemon running that spawns another process in the /dev/console bootstrap context in order to act as a remote desktop server. What I'm trying to accomplish here, is to run one of my processes as root in the current gui bootstrap context which is attached to the console. There are several guesswork states in MacOS (11.6, M1) that I've discovered. When you boot a machine, the loginwindow process is run in the bootstrap context of 88 (_windowserver). This makes sense because this process is created by WindowServer. The current console UID is discoverable by running: echo "show State:/Users/ConsoleUser" | scutil You can also introspect loginwindow using launchctl procinfo and friends. Note that, this is before any login has ever happened on the machine. In this state I can do anything in the gui bootstrap context by running this from the launchdaemon: launchctl asuser 88 myprogram In my case, I'm taking a screenshot using AppKit/CoreGraphics and checking some permissions. Once a user logs in, that loginwindow gets blessed by the OS and ownership is transferred to the logged in user. If you lock the machine, you're still in the same bootstrap context and everything works as expected. You can also log out and log into another user and everything works as I expect it to in terms of who controls loginwindow. However, as soon as you hit the "Switch user" button from the lock screen the following happens: A new loginwindow is spawned with the bootstrap context of root (UID of 0) launchctl asuser 0 myprog seems not to properly execute within the bootstrap context of root. My guess is that: 1 is a bug(?), the fast user switching bootstrap context should probably run as 88 rather than 0. A "fix" is running pkill loginwindow which nukes all gui sessions and restarts one loginwindow running in the bootstrap context of 88. This is of course not an acceptable solution. Doing the same thing using launchctl bootstrap gui/0 doesn't work either. I understand that the concept of "bootstrap gui/0" and "asuser 0" sounds nonsensical and it probably is. I'm just trying to find a working solution here. Is there a more proper way of being able run as root in the bootstrap context of a logged in/not yet logged in loginwindow? In case anyone is curious, I'm porting this to MacOS: https://fleetdeck.io
Posted
by
Post not yet marked as solved
3 Replies
619 Views
I have LaunchDaemon plist launching a x86_64 daemon, which worked so far on my M1 Mac mini running Big Sur, but right after the reboot from upgrading to macOS Monterey, I see error launching with EBADARCH error, but when I load the same plist by hand it worked. 2021-10-27 10:23:15.602649 (system/com.[redacted] [530]) : Could not find and/or execute program specified by service: 86: Bad CPU type in executable: 2021-10-27 10:23:15.602661 (system/com.[redacted] [530]) : Service could not initialize: posix_spawn([redacted]) EBADARCH error: 0x6f: Invalid or missing Program/ProgramArguments 2021-10-27 10:23:15.602666 (system/com.[redacted] [530]) : initialization failure: 21A559: xpcproxy + 23196 [815][D33C7462-5256-38E5-AFD4-A1FF694581F3]: 0x6f 2021-10-27 10:23:15.602668 (system/com.[redacted] [530]) : Service setup event to handle failure and will not launch until it fires. 2021-10-27 10:23:15.602671 (system/com.[redacted] [530]) : Missing executable detected. Job: 'com.[redacted]' Executable: '[redacted]'
Posted
by
Post not yet marked as solved
2 Replies
596 Views
I have a Safari Web Extension that communicates with its native App through UserDefaults within an App Group. The WebExtensionHandler is also used to carry out other functions for the Web Extension on request. I am currently troubleshooting a bug where a request from the Extension to the WebExtensionHandler remains unanswered. The bug only occurs on physical devices, in the simulator, it always behaves as expected. When XCode is attached to the App or App Extension process, the bug also does not trigger. When the Console App is used to monitor events on the device, the bug also does not trigger. Here is the code for the WebExtensionHandler: import SafariServices func respondWith(_ context: NSExtensionContext, string: String) { let response = NSExtensionItem() response.userInfo = [ SFExtensionMessageKey: string ] context.completeRequest(returningItems: [response], completionHandler: nil) } class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { var sharedPrefs = UserDefaults.init(suiteName: "group.eu.waiyu.app")! func beginRequest(with context: NSExtensionContext) { let item = context.inputItems[0] as! NSExtensionItem let message = item.userInfo?[SFExtensionMessageKey] as! Dictionary<String,Any> switch message["type"] as! String { // other cases... case "get_config": if let config = sharedPrefs.string(forKey: "config") { respondWith(context, string: config) } else { let defaultConfig = message["defaultConfig"]! respondWith(context, string: defaultConfig as! String) } default: respondWith(context, string: "Unknown Message type") } } } Even though it appears that something goes wrong when accessing sharedPrefs when the bug is triggered, other requests are answered correctly (before and after triggering the bug). As per some solutions to similar issues (https://stackoverflow.com/questions/38275395/failed-to-read-values-in-cfprefsplistsource-ios-10) I have tried different App Group IDs: the main Bundle ID, prefixed with "group." an ID different from both main bundle and extension bundle, prefixed with "group." "group.TEAMID." prefix (TEAMID being the developer team id) Is there anything I can try with regards to the code? Are there any other debugging workflows I can try that do not involve attaching to the device, that might allow me to capture more information about the bug?
Posted
by
Post marked as solved
2 Replies
439 Views
I have small integration test that is confirming behavior in XPC communications (leveraging NSXPCConnection) between a dummy XPC service and an XPC client. My test is flaky, which is indicating to me that I don't fully understand the nature of connections between services and clients, and I was hoping to get clarity as to what's happening in my test. My test involves the following steps. XCode Pre-Action: Load the plist for a dummy XPC service into launchctl. Create 2 XPC client objects (in the same client process), each with their own NSXPCConnection to the dummy service, and connect. Tell client 1 to disconnect, which calls NSXPCConnection.invalidate() Using client 2, send a message to the same dummy XPC service over it's own NSXPCConnection object. Wait for the echo response from the dummy XPC service XCode Post-Action: Unload the plist for the dummy XPC service from launchctl    func testMultipleConnections() {     let delegate1 = MockClientDelegate()     let delegate2 = MockClientDelegate()     let client1 = XPCMessagingClientFacade(withServiceName: serviceName, andXPCErrorHandler: {error in })     let client2 = XPCMessagingClientFacade(withServiceName: serviceName, andXPCErrorHandler: {error in })     client1.processMessageDelegate = delegate1     client2.processMessageDelegate = delegate2           _ = client1.connect()     _ = client2.connect()           _ = client1.disconnect()           delegate2.expectation = XCTestExpectation(description: "Message received from echo service")     _ = client2.sendMessage(ofMessageType: eMTAction_Uninstall, withData: ["dummy": "data"])     wait(for: [delegate2.expectation!], timeout: timeout)   } This test sometimes succeeds and sometimes fails. Sometimes, the test expectation at the bottom is fulfilled, and sometimes the timeout is hit. I have tested with excessively long timeouts to rule-out processing-time as as factor. I am suspecting that calling invalidate() on one NSXPCConnection object is somehow causing a separate connection between the same client and service process to also be invalidated. Is it even a valid use-case to have multiple NSXPCConnection objects between a single XPC Service and XPC Client? When NSXPCConnection.invalidate() is called, does it inherently mean nothing can connect and communicate anymore, or is it just for that specific connection? When invalidate() is called, what does launchctl do to manage that service? Does it shut it down and allow subsequent connection attempts to spool the service up again? Does it prevent from any connections from ever being made again?
Posted
by
Post not yet marked as solved
3 Replies
338 Views
I had my daemon service registered ( with keepalive true) to Mac OS and running in Catalina, after I upgraded to Bigsur the daemon did not start. when I tried to start manually I found that the daemon has been disabled. I had to load the daemon service with '-w' to enable it. in a customer machine, we cant ask them to do it manually. is there any way to stop disabling a daemon service during an upgrade to bigsur?
Posted
by
Post not yet marked as solved
6 Replies
473 Views
Hi, In our system we have a launch daemon that manages a child process that performs networking. We also have launch agents that perform GUI work in each user session. We'd like those agents to connect to the child process of the launch daemon via XPC. In the launchd.plist we can expose a MachServices port for the launch daemon itself but how do we expose a port for the child process? Is it possible for the Launch daemon to smuggle a declared port to its child process? Thanks! Johan
Posted
by
Post not yet marked as solved
1 Replies
370 Views
Hi, We are creating a macOS application that is built as a 'Bundle' and NOT as a Unix-style application. In a specific flow, we need to attach this process to a terminal session by creating one. Now, on this attached terminal, stdin/stdout etc would happen. We are using Objective C. Any pointers on how to go about this would be helpful.
Posted
by
Post marked as solved
1 Replies
344 Views
I'd like to get an indication about the context in which my process is running from. I'd like to distinguish between the following cases : It runs as a persistent scheduled task (launchDaemon/launchAgent) It was called on-demand and created by launchd using open command-line or double-click. It was called directly from command-line terminal (i.e. &gt; /bin/myProg from terminal ) Perhaps is there any indication about the process context using Objective-c/swift framework or any other way ? I wish to avoid inventing the wheel here :-) thanks
Posted
by
Post marked as solved
1 Replies
303 Views
I have a use case in which I have a launch daemon (as the XPC service) than needs to communicate with two XPC clients. Each of these clients has different functional cases for communication that do not overlap. Therefore, the NSXPCInterface for client A would be configured with a different protocol than the NSXPCInterface that would be configured for client B. Client A and Client B do not need to talk to each other; they each just need to communicate with the daemon. I am confused how to appropriately set up the NSXPCListener and NSXPCListenerDelegate on the daemon to support NSXPCConnections with proxy objects that adhere to varying interfaces to support these two clients. Is there a way for a single NSXPCListener (and associated delegate) to listen for connections requiring the exportedInterface to be different? Is there a way to send data through the NSXPCConnection that will allow the NSXPCListenerDelegate to conditionally determine which exported interface and object to configure? One idea I had was to have the daemon contain two NSXPCListeners. Each listener would be responsible for connections coming from the respective clients. Will this option work? If so, it is the advisable approach?
Posted
by
Post not yet marked as solved
8 Replies
598 Views
This question came from https://developer.apple.com/forums/thread/695826, where I saw crashes in AppKit if called without a GUI session. What troubles me from there is that our code is registered as a LaunchAgent (under /Library/LaunchAgents), and I was under the impression that a LaunchAgent only runs if a user logs into a GUI session. I tried at least ssh-only sessions and didn't see it launch automatically (I had to manually launch it through ssh to reproduce the crash). But the fact that we see thousands of crash reports coming from a few devices means somehow our LaunchAgent is trying to launch itself automatically &amp; repeatedly on these devices, while there is no GUI session so it keeps crashing. So, maybe there is a legit way to reproduce the scenario, to launch a LaunchAgent without a GUI session that I'm not aware of?
Posted
by
Post not yet marked as solved
2 Replies
430 Views
As per my research I found that there is no way to open general settings app but it is possible with openSettingsURLString. Can I use openURL API with options to open general settings? And also how can we request iOS API team to provide such support in future as this is so many time generated request.
Posted
by
Post marked as solved
8 Replies
468 Views
Hi! I wrote a backup console application. It does use ssh/sshfs to access a web server via public key. Also it does send an SMTP-mail when finished. If the process is started via launchctl load DAEMON it works always properly (RunAtLoad is true). But when the daemon is called automatically at night it does not always work. In my log I get these errors: ssh: connect to host SERVERURL port 22: Undefined error: 0 and Failed sending: NIOConnectionError(host: "mail.mydomain", port: 25, dnsAError: Optional(NIOCore.SocketAddressError.unknown(host: "mail.mydomain", port: 25)), dnsAAAAError: Optional(NIOCore.SocketAddressError.unknown(host: "mail.mydomain", port: 25)), connectionErrors: []) it does run on a MacMini M1 with macOS 12.2. Any clue what's wrong or how to find the reason of this issue? PS. On another MacMini (Intel) with macOS 11.6 the backup works since a year but there is always an admin user logged in.
Posted
by
Post not yet marked as solved
1 Replies
444 Views
I'm trying to use task_for_pid in a project but I keep getting error code 5 signaling some kind of signing error. Even with this script I cant seem to get it to work. #include <mach/mach_types.h> #include <stdlib.h> #include <mach/mach.h> #include <mach/mach_error.h> #include <mach/mach_traps.h> #include <stdio.h> int main(int argc, const char * argv[]) {   task_t task;   pid_t pid = argc >= 2 ? atoi(argv[1]) : 1;   kern_return_t error = task_for_pid(mach_task_self(), pid, &task);   printf("%d -> %x [%d - %s]\n", pid, task, error, mach_error_string(error));   return error; } I've tried signing my executables using codesign and also tried building with Xcode with the "Debugging Tool" box checked under hardened runtime. My Info.plist file includes the SecTaskAccess key with the values "allowed" and "debug." Hoping someone can point me towards what I'm missing here. Thanks!
Posted
by
Post marked as solved
2 Replies
295 Views
I have a few questions regarding daemons. Indeed, even the macos developer center has limited information resources. I want to develop an application daemon that runs after system boot without login. a) a Daemon; Is it a simple console application combined with a plist? Because there are almost no tutorials on daemon development related to xcode. If there is a code sample reference, can you share it here? b) Can daemons be downloaded from the app store? Because there must be a software that I can offer to everyone through the app store. Is the installation automatic like other app store apps? If anyone has experience and can share it, I would be very grateful. c) I am working on an api related to mirroring the screen to android phone. Do you think a daemon has full access to wifi/ble and screen capture APIs? I would be very happy to hear your suggestions.
Posted
by
Post not yet marked as solved
5 Replies
386 Views
We are noticing a strange behavior with our app and launchctl, not sure yet if it is only in M1 Monterey Macos. We have a launchctl plist that has not changed for a while that allows the app to restart after a crash via the Keepalive key &amp;lt;key&amp;gt;KeepAlive&amp;lt;/key&amp;gt; &amp;lt;dict&amp;gt; &amp;lt;key&amp;gt;SuccessfulExit&amp;lt;/key&amp;gt; &amp;lt;false/&amp;gt; What we are noticing is that the app crashes and instead of the app reopening via launchctl , an Apple crash report window opens. The app is used in several headless environments and we are trying to understand asap how to deal with this change of behavior. Any input will be helpful. Is there an option in xcode to modify this kind of behavior ? For example set the app to show a crash report instead of launchctl executing. Is there a way to trace why launchctl did not reopen the app ? Does it make a difference if the app is a debug version ? We have noticed no difference between Release and Debug versions, same behavior.
Posted
by
Post not yet marked as solved
1 Replies
215 Views
I refer to this article: https://developer.apple.com/forums/thread/129752 extension Cmd {   static func launch(tool: URL, arguments: [String], completionHandler: @escaping (Int32, Data) -> Void) throws {     let group = DispatchGroup()     let pipe = Pipe()     var standardOutData = Data()     group.enter()     let proc = Process()     proc.executableURL = tool     proc.arguments = arguments     proc.standardOutput = pipe.fileHandleForWriting     proc.terminationHandler = { _ in       proc.terminationHandler = nil       group.leave()     }     group.enter()     DispatchQueue.global().async {       // Doing long-running synchronous I/O on a global concurrent queue block       // is less than ideal, but I’ve convinced myself that it’s acceptable       // given the target ‘market’ for this code.       let data = pipe.fileHandleForReading.readDataToEndOfFile()       pipe.fileHandleForReading.closeFile()       DispatchQueue.main.async {         standardOutData = data         group.leave()       }     }     group.notify(queue: .main) {       completionHandler(proc.terminationStatus, standardOutData)     }     try proc.run()     // We have to close our reference to the write side of the pipe so that the     // termination of the child process triggers EOF on the read side.     pipe.fileHandleForWriting.closeFile()   } } run shell : try Cmd.launch(tool: URL(fileURLWithPath: "/usr/bin/which"), arguments: ["docker"]) { (status, outputData) in         let output = String(data: outputData, encoding: .utf8) ?? ""         print("done, status: \(status), output: \(output)")       } the result print: done, status: 1, output:  i had remove sandbox and use this code in my mac app. and return value is empty string. I tried running this script using https://github.com/kareman/SwiftShell and got the same result
Posted
by
Post not yet marked as solved
3 Replies
266 Views
I am trying to pass an array of C-structs to an XPC Service, but the service receives only the first element. Following is the C struct struct MyStruct { char *name; unsigned char v1; unsigned char v2; Status status; // a c-style enum }; and I am using it like this struct MyStruct structs[3] = {{"name1", 0, 0, success}, {"name2", 1,1, success}, {0}}; [[_connectionToService remoteObjectProxy] doSomething:structs]; and doSomething is declared as - (void)doSomething: (struct MyStruct[]) structs; The document Creating XPC Services mentions that C structures and arrays containing only the types listed above are supported, but I am unable to get it to work even for an array of c-strings or ints. Also, there's an API for making synchronous RPC calls but there is no documentation available for it. - (id)synchronousRemoteObjectProxyWithErrorHandler:(void (^)(NSError *error))handler It does seem to block but only if the remote method has a reply block. Is this the expected behaviour? And is it safe to cache the proxy object returned by this method?
Posted
by
Post not yet marked as solved
12 Replies
661 Views
Hi, I’d like to perform client-side certificate authentication from https based connection in macOS. I’m using the method didReceiveChallenge from URLSession. However, I cannot read the keychain directly since my process is running as Daemon, and my client certificate reside in login keychain. So I've followed the guidance from this question https://developer.apple.com/forums/thread/106851, and sent this authentication request to a user-based process which is running in the current user so it has access to the keychain. After I acquire the NSURLCredential object, I’d like to return it back to the Daemon, so it may run the completionHandler with that credential. However, After I successfully create the NSURLCredential in the user process, and send it back using some reply callback. It looks like the object didn’t serialized properly and I get the following error : Exception: decodeObjectForKey: Object of class "NSURLCredential" returned nil from -initWithCoder: while being decoded for key <no key> Here’s my client side code ( I made sure that the server side create a valid NSURLCredential object). and the problem occur after I send the XPC request, right when i’m about to get the callback response (reply) - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate) { [myXpcService getCertIdentityWithAcceptedIssuers:challenge.protectionSpace.distinguishedNames withReply:^(NSURLCredential *cred, NSError *error) { if (error != nil) { completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); } else { completionHandler(NSURLSessionAuthChallengeUseCredential, cred); } }]; } Perhaps anybody can tell me what did I do wrong here ? Does XPC is capable to pass complex objects like NSURLCredentials ? thanks !
Posted
by