Probably. Both of your examples seem kinda wonky to me.
Yeah this is garbage code anyway. I'll prolly use a singleton or instantiate it in the App stuct.
You have double dots in that screen shot, that is, this:
I already fixed this :) But it did not fixed it.
I put the code into this repo: https://github.com/tony-go/NetworkMonitor
The only missing part is the ~/Library/LaunchAgents/W4MF6H9XZ6.com.tonygo.NetworkMonitorApp.xpc.plist file:
<!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>W4MF6H9XZ6.com.tonygo.NetworkMonitorApp.xpc</string>
<key>ProgramArguments</key>
<array>
<string>/Users/tonygorez/Desktop/Builds/Release/NetworkMonitor</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
<key>MachServices</key>
<dict>
<key>com.tonygo.NetworkMonitorAgent</key>
<true/>
</dict>
</dict>
</plist>
Post
Replies
Boosts
Views
Activity
Note: I used "$(TeamIdentifierPrefix)com.tonygo.NetworkMonitorApp.xpc" and not "$(TeamIdentifierPrefix).com.tonygo.NetworkMonitorApp.xpc"
Hey 👋
The next to me is to enable the App Sandbox again and use App groups.
So I did the following:
Create an app group on Xcode
Change the entitlements of each target
Change the MACH_SERVICE_NAME var (used to establish connection)
let MACH_SERVICE_NAME = "W4MF6H9XZ6.com.tonygo.NetworkMonitorApp.xpc"
Change the name of launchd agent in the .plist and change the name of the file
➜ LaunchAgents launchctl list | grep tonygo\
49603 0 W4MF6H9XZ6.com.tonygo.NetworkMonitorApp.xpc
I see logs of the loaded agent, But I still have the lookup error...
Did I miss something @eskimo ?
I spotted it; this is probably the moment you throw virtual tomatoes at me, haha.
This seems to come from how I instantiate the Client class:
The code that does not work:
struct ContentView: View {
@State private var networkStatus: String = "Off"
var body: some View {
Text("Network status: \(networkStatus)")
.onAppear {
NetworkMonitorXPCClient().getNetworkStatus { status in
DispatchQueue.main.async {
self.networkStatus = status ? "Online" : "Offline"
}
}
}
}
}
The code that works:
struct ContentView: View {
@State private var networkStatus: String = "Off"
private var xpc = NetworkMonitorXPCClient()
var body: some View {
Text("Network status: \(networkStatus)")
.onAppear {
xpc.getNetworkStatus { status in
DispatchQueue.main.async {
self.networkStatus = status ? "Online" : "Offline"
}
}
}
}
}
This maybe due to how the onAppear code is executed?
You’re doing that from Terminal app, logged in to the same GUI login context as the client app, right?
Yeah.
Do you see any additional log messages in the system log when you run your app and try to connect?
No, but I observe another thing, once the macOS is up, I see two launchd agents in the console.
➜ ~ launchctl list | grep tonygo
22718 0 application.com.tonygo.NetworkMonitorApp.138426740.138426852.1D8FCF73-1582-44D3-AA62-4888F3AC0D07
22433 0 com.tonygo.NetworkMonitorAgent
But this probably the app itself as, the build identifier is different and even if I comment the whole NSXPCConnection logic and re-run (after a clean build) again, I see the Xcode agent. So this is probably not related.
Maybe should I publish the code somewhere?
As to your invalidation problem, that’s likely because the service name isn’t being registered properly. What does your agent’s property list look like? And how are you loading it?
The code is:
import Foundation
import OSLog
class NetworkMonitorXPCService: NSObject, NetworkMonitorXPCProtocol, NSXPCListenerDelegate {
func getNetworkStatus(reply: @escaping (Bool) -> Void) {
// Implement your logic to determine the network status
let networkStatus: Bool = true
reply(networkStatus)
}
/// This method is where the NSXPCListener configures, accepts, and resumes a new incoming NSXPCConnection.
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
Logger.agent.debug("In listener")
// Configure the connection.
// First, set the interface that the exported object implements.
newConnection.exportedInterface = NSXPCInterface(with: NetworkMonitorXPCProtocol.self)
Logger.agent.debug("After Exported Interface")
// Next, set the object that the connection exports. All messages sent on the connection to this service will be sent to the exported object to handle. The connection retains the exported object.
newConnection.exportedObject = self
Logger.agent.debug("After Exported Object")
// Resuming the connection allows the system to deliver more incoming messages.
newConnection.resume()
Logger.agent.debug("After Exported Resume")
// Returning true from this method tells the system that you have accepted this connection. If you want to reject the connection for some reason, call invalidate() on the connection and return false.
return true
}
}
Logger.agent.info("Start agent")
let delegate = NetworkMonitorXPCService()
let listener = NSXPCListener.init(machServiceName: MACH_SERVICE_NAME) // declared as: let MACH_SERVICE_NAME = "com.tonygo.NetworkMonitorAgent"
listener.delegate = delegate
listener.resume()
Logger.agent.info("Agent started")
RunLoop.main.run()
I have this .plist file:
<!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.tonygo.NetworkMonitorAgent</string>
<key>ProgramArguments</key>
<array>
<string>/Users/tonygorez/Desktop/Builds/Release/NetworkMonitor</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
<key>MachServices</key>
<dict>
<key>com.tonygo.NetworkMonitorAgent</key>
<true/>
</dict>
</dict>
</plist>
For the loading I just run:
launchctl load ~/Library/LaunchAgents/com.tonygo.NetworkMonitorAgent.plist
➜ ~ launchctl list | grep tonygo
11588 0 com.tonygo.NetworkMonitorAgent
I also take a look at the console. (see joined screen)
Again thanks @eskimo , for your answers :)
Before diving into SMAppService, I try to load the agent manually and start a macOS app that will connect with the Agent. (I'd like to use a minimalist setup at first and add layers as much as I face limitations, this is the way I'd like to discover new topics :) )
I faced several issues:
Sandbox: NetworkMonitorApp(2330) deny(1) mach-lookup com.tonygo.NetworkMonitorAgent from the agent log, then I add com.apple.security.temporary-exception.mach-lookup.global-name (I Imagine that SMAppService will remove this) - The message dissapeard.
I still have a The connection to service named com.tonygo.NetworkMonitorAgent was invalidated from this process. from th macOS app.
Note: I also authorize Server and Client connextion from sandbox or even remove the sandbox, but it did not change...
Either it is not possible at all to do this kind of unsafe XPC connection, or I miss something :)
Thanks a lot :) @eskimo
Thus, only your app can connect to it.
So when my XPCS service is up, no potential men in the middle could try to connect? Where I can find official Apple documentation about this?
If your named XPC endpoint is available elsewhere, say you’re building a launchd agent [...]
Oh, that is the difference then.
Disabling sandbox for the Service worked.
Then I try to re-enable it and authorize this:
But it did not worked...
Is it acceptable to remove the sandbox for an XPC service?
Note: I know that calling SecCodeCopyGuestWithAttributes is not enough, my goal is to use SecCodeCopyStaticCode and then perform a few checks.
Hi @eskimo 👋
Thank you for this answer.
I tried to reproduce this little project on Xcode but still got into the same trouble.
I recorded my screen and uploaded it here: https://www.youtube.com/watch?v=Cn0VOjU7MJY
Maybe I created the breakpoint in the wrong place?
Edit:
(lldb) b -[NSView hitTest:]
Breakpoint 1: where = AppKit`-[NSView hitTest:], address = 0x0000000183857e18
(lldb) process launch -e /dev/null --
Process 4125 launched: '/System/Applications/Notes.app/Contents/MacOS/Notes' (arm64e)
Process 4125 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x000000018c093e18 AppKit` -[NSView hitTest:]
AppKit`-[NSView hitTest:]:
-> 0x18c093e18 <+0>: pacibsp
0x18c093e1c <+4>: sub sp, sp, #0x70
0x18c093e20 <+8>: stp x24, x23, [sp, #0x30]
0x18c093e24 <+12>: stp x22, x21, [sp, #0x40]
0x18c093e28 <+16>: stp x20, x19, [sp, #0x50]
0x18c093e2c <+20>: stp x29, x30, [sp, #0x60]
0x18c093e30 <+24>: add x29, sp, #0x60
0x18c093e34 <+28>: mov x19, x0
Target 0: (Notes) stopped.
(lldb) p $arg1
(unsigned long) $2 = 4312972736
(lldb) po $2
<NSTitlebarContainerView: 0x10112bdc0>
(lldb) c
Process 4125 resuming
-- later
Process 4125 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x000000018c093e18 AppKit` -[NSView hitTest:]
AppKit`-[NSView hitTest:]:
-> 0x18c093e18 <+0>: pacibsp
0x18c093e1c <+4>: sub sp, sp, #0x70
0x18c093e20 <+8>: stp x24, x23, [sp, #0x30]
0x18c093e24 <+12>: stp x22, x21, [sp, #0x40]
0x18c093e28 <+16>: stp x20, x19, [sp, #0x50]
0x18c093e2c <+20>: stp x29, x30, [sp, #0x60]
0x18c093e30 <+24>: add x29, sp, #0x60
0x18c093e34 <+28>: mov x19, x0
Target 0: (Notes) stopped.
(lldb) po $2
<NSTitlebarContainerView: 0x10112bdc0>
(lldb) c
-- later, after pausing --
(lldb) po $2
<NSTitlebarContainerView: 0x10112bdc0>
I tried outside of Xcode, attaching the debugger to the Notes app:
(lldb) b -[NSView hitTest:]
Breakpoint 1: where = AppKit`-[NSView hitTest:], address = 0x0000000183857e18
(lldb) process launch -e /dev/null --
Process 4125 launched: '/System/Applications/Notes.app/Contents/MacOS/Notes' (arm64e)
Process 4125 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x000000018c093e18 AppKit` -[NSView hitTest:]
AppKit`-[NSView hitTest:]:
-> 0x18c093e18 <+0>: pacibsp
0x18c093e1c <+4>: sub sp, sp, #0x70
0x18c093e20 <+8>: stp x24, x23, [sp, #0x30]
0x18c093e24 <+12>: stp x22, x21, [sp, #0x40]
0x18c093e28 <+16>: stp x20, x19, [sp, #0x50]
0x18c093e2c <+20>: stp x29, x30, [sp, #0x60]
0x18c093e30 <+24>: add x29, sp, #0x60
0x18c093e34 <+28>: mov x19, x0
Target 0: (Notes) stopped.
(lldb) p $arg1
(unsigned long) $2 = 4312972736
(lldb) po $2
<NSTitlebarContainerView: 0x10112bdc0>
It seems to work in this context.