Hi,
I'm developing an macOS app which includes an agent (registered as login item) which is intended to run for entire duration of user's login session.
The agent's bundle also includes few application extensions. The application is intended to be distributed outside of App Store. It is not going to be sandboxed but rather notarized, so I'm using hardened runtime.
I want to add some application extensions (for example: a file provider etension) to be bundled with the agent.
The extensions are sandboxed and belong to the same application group as main application and the agent.
Extensions should do some IPC calls on the running agent process.
I think the most convenient solution for the IPC would be to use the XPC service, so, in the agent, I'am creating an XPC listener registered to mach service name.
Now I want to connect to the XPC service provided by the agent from the app extensions. This, however, fails with the following error:
Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named abcd.service was invalidated: failed at lookup with error 159 - Sandbox restriction."
My application bundle has now the following structure:
MainApp.app --- main application bundle (hardened runtime)
Contents/Library/LoginItems/agent.app --- agent with XPC service (hardened runtime)
.../agent.app/Contents/PlugIns/AppExt1.appex --- app extension 1 (sandboxed)
.../agent.app/Contents/Plugins/AppExt2.appex --- app extension 2 (sandboxed)
Searching through the forum I've found another post, which advises to bundle the XPC service within the app extension to mitigate this issue. This, however, does not seem like a viable solution for my problem: what I need is to call the code on the running agent instance.
As an alternative I considered to create a unix domain socket in the application group container and use that for communication between the agent and its extensions. XPC however is more convenient so if there is any way to make it working for the above scenario, I would be interested to learn about it.
Post not yet marked as solved
This specifically seems to happen when my network extension is spawned by launchd, but has not actually been connected. (That is my conclusion based on the evidence: ps shows the process existing, but the logs show that main() hasn't run yet, let alone the proxy provider's init(). Without being able to debug launchd, I would say the situation is that launchd has said "yes this XPC port exists, when you try to connect to it I will send it on over to the extension, and thereafter you two will happily communicate directly," but the process hasn't gotten around to accepting XPC connections.) This seems to be most likely to happen when the extension crashes, or I kill -9 it to see how it handles respawning.
I have a little CLI tool that talks (over XPC, of course) to the extension, mainly to say "Hi are you alive?" If the extension is not loaded, the XPC connection fails, as expected, and my tool says "NOT YET." If it is loaded and running, the XPC connection succeeds, as expected, and I get back a response of true.
So my first question is: is this expected behaviour?
My second question is: is there a way to do an XPC connection with a timeout?
Post not yet marked as solved
I'm trying to build something wherein I can redirect all traffic from a given application to a specified network interface. As an example use case, because I'm stuck with DSL for the time being, I don't want to saturate my line uploading every day things like dropbox or whatnot, so I want to be able to say, all traffic from dropbox should go through the wifi/personal hotspot. I can do this somewhat with squidproxy and specifying each application to go through that proxy -- but that relies on the app even allowing that kind of configuration and it's more work than I think it needs to be.
As an example of the same concept but for audio, see SoundSource by https://rogueamoeba.com/
With soundsource you can direct audio per application to any interface. I want to do the same, but for network traffic. Bonus I can get granular enough to direct outgoing and incoming to different devices on the same app.
But this is an area of systems programming I always felt the least accessible and I'm not really sure where to start reading.
First, I guess I should ask, is this even possible with macos/darwin at this time? I know in linux I could just namespace each application, but as far as I know, macos lacks that kind of functionality.
Cheers
Unless I'm missing something (always possible)... there is no way to tell if you get a valid proxy back -- the error handler is asynchronous, and I don't see a way to say "this proxy is valid."
Am I missing something?
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.
Post not yet marked as solved
Hi,
I'm writing an XPC Service hosted in a container app.
This service is expected to trigger IPC when some URL of interest become reachable. I'm using SCNetworkReachability (Reachability class provided as sample code from Apple).
The reachability notification runs fine when running from the container app.
However the XPC Service is never triggered of any network change.
I'm suspecting something related to RunLoop or RunLoopMode (XPCListener is instantiated with serviceListener) but cannot find any fix.
I disabled sandboxing without success (and anyway it runs fine with sandboxed container + network client entitlement).
Any suggestion ?
Hi,
I’m writing a network extension for macOS using the following pattern:
Network extension with ID com.company.app.extension
XPC Service with ID com.company.app.controller
Container app with ID com.company.app.container
First 2 are contained in the 3rd
All of 3 are sandboxed & share the same com.company.app AppGroup.
XPC Service uses network (client) entitlement to fetch settings & control the extension.
The app need to support managed preferences as well.
I read many posts in this forum, but I’m confused about using NSUserDefaults accross those processes.
Pb 1 - standardsUserDefaults vs initWithSuiteName
I noticed that to observe defaults using KVO I need to use initWithSuiteName:@"com.company.app" (or addSuiteName).
Observing standardsUserDefaults alone will never trigger any event. This is the first confusion because my understanding was that KVO observation wasn’t restrincted to suites.
Pb 2 - AppGroup ‘group.’ prefix
If I observe a suite named ‘com.company.app’ from the container app or XPC Service I get error : [User Defaults] Couldn't read values in CFPrefsManagedSource<> (Domain: com.company.app, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: No): accessing preferences outside an application's container requires user-preference-read or file-read-data sandbox access
This can be fixed using ‘group.com.company.app’ suite (both in the code and AppGroup entitlement). However if I use the same AppGroup for extension it will fail loading with error code OSSystemExtensionErrorValidationFailed.
Checked the provisioning profiles, they all map to the same ID in Dev portal. Including the TeamID in the suite name will produce the same situation.
The only way to load the extension is to use AppGroup com.company.app. This again is confusing because Dev portal force the ‘group.’ prefix. I can’t figure out how to use the same suite name for all processes.
Pb 3 - Inter-process synchronisation
Based on previous conclusion the situation is both container & controller use AppGroup (TeamID).group.com.company.app and addSuiteNamed:@"group.com.company.app" for observing & updating the defaults.
Each process can observe its own defaults updates but they do not synchronize between container app and XPC Service.
This is the most frustating part. The documentation says:
NSUserDefaultsDidChangeNotification is posted whenever any user defaults changed within the current process, but is not posted when ubiquitous defaults change, or when an outside process changes defaults. Using key-value observing to register observers for the specific keys of interest will inform you of all updates, regardless of where they're from.
Did I missed some steps ?
Post not yet marked as solved
Hello,
I want to build a developer tool and I have the following setup in mind. The tool consists of
a macOS app with a GUI
a background service (XPC service?) that performs the "heavy lifting"
and a framework ("Client.framework") that can be used by the developer to build customisations based on the background service. These customisations are supposed to be run as a command line tool, in the swift REPL or as a Playground.
Both the macOS GUI app and the Client.framework are kind of clients of the background service.
I did some experiments with an XPC service hosted by the macos app. During these experiements I was not able to connect to the XPC from the Client.framework (tried in the swift REPL, as a command line tool and a Playground). As soon as I try to open the connection to the XPC, the connection's invalidationHandler is called. Accesing the XPC from within the macOS GUI app ("host" app) works fine.
How can I implement this setup? Is an XPC service the right choice for my background service? Do I need to configure the XPC in a specific way to make it accessible from a framework used in the swift REPL, a command line tool or an Xcode Playground?
Thanks!
steven
Post not yet marked as solved
My standard "native" Mac app uses Catalyst helper. Helper is registered as Login Item via SMLoginItemSetEnabled. I tried to establish XPC communication between these process but I failed.
Is it possible to configure XPC connection between these two apps (mac host and catalyst helper)?
As far as I can understand it is possible to create XPC connection in Catalyst via passing listener endpoint. However how to send this endpoint between helper and host app? NSXPCListener.init(machServiceName:) is not available for Catalyst app.
Post not yet marked as solved
I have an XPC connection that I want to know if I should trust using the following code. Does this look like a workable secure approach?
func connectionIsValid(connection: NSXPCConnection) -> Bool {
let checker = CodesignChecker()
var localCertificates: [SecCertificate] = []
var remoteCertificates: [SecCertificate] = []
let pid = connection.processIdentifier
do {
localCertificates = try checker.getCertificatesSelf()
remoteCertificates = try checker.getCertificates(forPID: pid)
} catch let error as CodesignCheckerError {
NSLog(CodesignCheckerError.handle(error: error))
} catch let error {
NSLog("Something unexpected happened: \(error.localizedDescription)")
}
NSLog("Local certificates: \(localCertificates)")
NSLog("Remote certificates: \(remoteCertificates)")
let remoteApp = NSRunningApplication.init(processIdentifier: pid)
if remoteApp != nil && !remoteCertificates.isEmpty {
let policy = SecPolicyCreateBasicX509()
var optionalTrust: SecTrust?
let status = SecTrustCreateWithCertificates(remoteCertificates as AnyObject,
policy,
&optionalTrust)
guard status == errSecSuccess else {
NSLog("failed evaluating trust")
return false
}
let trust = optionalTrust!
var secResult = SecTrustResultType.invalid
SecTrustGetTrustResult(trust, &secResult)
if(secResult == .proceed || secResult == .unspecified) {
let names = remoteCertificates.map { commonName(cert:$0) }
let validCert1 = ["Apple Development: john.doe(at)example.com (XY12XY12X)", "Apple Worldwide Developer Relations Certification Authority", "Apple Root CA"]
if(names == validCert1) {
NSLog("Found a valid client (fingerprint #1)")
return true
}
let validCert2 = ["Developer ID Application: John Doe (XY13XY13X)", "Developer ID Certification Authority", "Apple Root CA"]
if(names == validCert2) {
NSLog("Found a valid client (fingerprint #2)")
return true
}
return false
} else {
NSLog("Got invalid secResult: \(secResult.rawValue)")
}
return false
}
func commonName(cert: SecCertificate) -> String {
var commonName: CFString?
SecCertificateCopyCommonName(cert, &commonName)
return commonName as String? ?? ""
}
As the description of XPC says that it can be used for inter process communication mechanism, what exactly the inter process means?
Can it be used to create shared memory between any type of processes (ex. Swift Process (App) and any other language process) or it is for strictly App to App (swift to swift) communication?
I have a xpc module (wrote in Swift using NSXPCConnection), it works well with test application (simple swift test app), my plan is to put this module under XPCService of a DAL plugIn, since the plugin written in C++, I created an Objective-C dylib which response for talking to the XPC, and this dylib using NSXConnection to activate the XPC module(as the Swift test App), it exports C API to the
plugin.
Somehow when application using the plugin, the plugin call the API of the dylib to activate the XPC, but the XPC won't get loaded (from Activity Monitor).
Any idea to get this working? I cannot put XPCService folder inside the Obj-C dylib instead of inside the plugin bundle, and I don't want load the xpc as daemon, want it be loaded as plugin demanded.
Adding Obj-C into current C plugin is pretty headache, is there any C++ version NSXPConnection for this kind of situation?
=======this is the code in the dylib for activating the connection ======
- (int) initXPC
{
connection = [[NSXPCConnection alloc] initWithServiceName:@"com....."];
connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MyProtocol)];
[connection resume];
self->started = false;
NSLog(@"😂 XPC connection setup, result:%@", ((connection == nil) ? @"Failed":@"Succeed!") );
return connection != nil ;
}
Thanks
Steven
Post not yet marked as solved
When an app is running on a Mac, it can add a helper app to its bundle, in the Contents/Library/LoginItems.
This app can launch this helper app by running SMLoginItemSetEnabled.
This helper app is then always open by macOS after restarts.
What bothers me is that there is no visibility on all these apps. They do not appear in any of the LaunchDaemons/LaunchAgents directories, nor in the System Preferences/Users/LoginItem list.
So I have a few questions :
are strictly all apps started in such a way XPC services ?
how can I list all such helper apps? Running "launchctl list" seems to list all processes, not simply all such processes, in spite of the help description "Lists information about services". This description therefore appears incorrect to me, am I missing something?
How can I prevent these apps from being launched at login/startup? Is "launch unloads" the right way to go about it?
Thanks
Post not yet marked as solved
Is it possible we embed a windowcontroller inside an XPC module and pop/hide the window as demanded? right now the window cannot pop due to not in main thread.
What is the better alternative under the condition that xpc cannot modify the caller for permission.
Post not yet marked as solved
Hi all, i am kind of new in apple, and I am developing an app that fetch realtime data from a market, and display in the graphical macOS X app.
The thing is, is was thinking in separate the app in pieces, to prevent crashes from the network, and I was thinking create a XPC service that manage the network connection to the realtime data service, but reading, looks like the xpc can be shutdown by the system if resources are need. There is a way to prevent this?
XPC service should not be the natural way to implement this? or there is another way
Thanks in advance
Post not yet marked as solved
Hi, I was wondering if there's any limitation for the context where I initialize my xpc service.
This is the code that initialize my xpc service :
listener_ = [[NSXPCListener alloc]
initWithMachServiceName:@"com.bla.bla"];
xpcService *delegate = [xpcService new];
listener_.delegate = delegate;
[listener_ resume];
[[NSRunLoop mainRunLoop] run];
Doing it from the main method and everything works just fine. However, when calling it from different method(main)/thread(main thread)... It doesn't accept remote calls although it seems like the listener was properly initialized.
I even tried to wrap this code to run on the main thread using the following wrapper
dispatch_sync(dispatch_get_main_queue(), ^{
listener_ = [[NSXPCListener alloc]
initWithMachServiceName:@"com.bla.bla"];
xpcService *delegate = [xpcService new];
listener_.delegate = delegate;
[listener_ resume];
}
where the [[NSRunLoop mainRunLoop] run]; is called from the main method...
So my question is what are the requirements to make the XPC work.. is it mandatory to call it from the main method ?
I don't want the XPC process to be killed and restarted
Post not yet marked as solved
Software Update just hangs on No keys matching () available for download if we run it as root. neither returning success nor failure on MacOS Monterey (OS Version 12.0.1)
SUOSUNotificationManagerController having XPC issue saying No Such Process.
faced this issue in normal XPC connection also. root process trying to connect user process throws the same error
when it will be fixed. is there any work around for root to install via software update
log trace:
ues-mac-testl softwareupdate[2710]: SUOSUNotificationManagerController: Error connecting to notification manager service to set authorization: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.SoftwareUpdateNotificationManagerService was invalidated: failed at lookup with error 3 - No such process." UserInfo={NSDebugDescription=The connection to service named com.apple.SoftwareUpdateNotificationManagerService was invalidated: failed at lookup with error 3 - No such process.}
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?
I apologize for attempting this monstrosity, but... It is forced on me.
I have a .jar implementing logic that I receive prebuilt. This .jar exports some API you can use (... in Java...) to request information about file-system items you hand in as paths.
This .jar is compatible with Java 11, and runs with the "Zulu" Java VM.
I need to "wrap" it in some way that will behave like a global daemon, launched and managed by launchd, available to other components (apps, user-agents and global-daemons) in our product.
Running it as a global daemon is a breeze - simply place a .plist in /Library/LaunchDaemons/myMonster.plist and have the java -jar <path to my .jar> arguments, throw in a 'keep alive' option, and it runs.
Now... It makes sense for other components to pass it "queries" and receive "results" via XPC connection. First, because this way I could deny connection to unknown components, I could have a secure connection, and also integrate nicely from the other components ObjC code.
However... XPC isn't something available in JDK, and the actual executable launched is the Zulu java command binary of course, that I can't modify.
So... I tried to use JNA (Java Native Access) and (with much tears and sweat) get my java code to create an xpc connection (as client! not "service") to another XPC Service already running.
Also, I was only able to do it via xpc.h (the old C API. not ObjC NSXPCConnection as of yet).
The documentation on old C-style XPC Services is very thin, almost nothing... and the only thing about Creating an XPC Service of this style says:
// If you are writing a low-level (C-based) XPC service, implement a minimal main function to register your event handler, as shown in the following code listing. Replace my_event_handler with the name of your event handler function.
int main(int argc, const char *argv[]) {
xpc_main(my_event_handler);
// The xpc_main() function never returns.
exit(EXIT_FAILURE);
}
Which of course, I can't do! I don't control the process 'main()' entry point (it's java...) and I can't block anything.
So here's my question:
Where in the lifecycle of a Java program can I call on my native code to set up The XPC Service?
Is there a non-blocking alternative to xpc_main(my_event_handler) I can use to start my service?
I know this calls for multi-disciplinary knowledge but any hint or idea will be greatly appreciated.
Thanks!