I am building a Mac app that launch a GUI helper app and use XPC to communicate between them.
Main app start a XPC Listener using NSXPCListener(machServiceName: "group.com.mycompany.myapp.xpc")
Launch the helper app
Helper app connect to the XPC service and listen command from main app.
What I observe is the app seems can start XPC listener while I run it via Xcode. If I run the app using TestFlight build, or via the compiled debug binary (same one that I use on Xcode), it cannot start the XPC service. Here is what I see in the Console:
[0x600000ef7570] activating connection: mach=true listener=true peer=false name=group.com.mycompany.myapp.xpc
[0x600000ef7570] listener failed to activate: xpc_error=[1: Operation not permitted]
Both main app and helper app are sandboxed and in the same App Group - if they were not, I cannot connect the helper app to main app. I can confirm the entitlement profiles did contain the app group.
If I start the main app via xcode, and then launch the helper app manually via Finder, the helper app can connect to the XPC and everything work.
It is not related to Release configuration, as the same binary work while I am debugging, but not when I open the binary manually.
For context, the main app is a Catalyst app, and helper app is an AppKit app. To start a XPC listener on Catalyst, I had do it in a AppKit bridge via bundle.
Given the app worked on Xcode, I believe this approach can work. I just cannot figure out why it only work while I am debugging.
Any pointer to debug this issue is greatly appreciated. Thanks!
Processes & Concurrency
RSS for tagDiscover how the operating system manages multiple applications and processes simultaneously, ensuring smooth multitasking performance.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hello,
I'm experiencing an issue with my app where it's being terminated by the system with a watchdog violation during back-to-back messaging operations. I've analyzed the crash logs but would appreciate additional insights on optimizing my approach. I'd appreciate any insights on how to resolve this problem.
Crash Details:
Exception Type: EXC_CRASH (SIGKILL)
Termination Reason: FRONTBOARD with code 0x8BADF00D
Error: "scene-update watchdog transgression: app exhausted real time allowance of 10.00 seconds"
Reproduction Steps:
User A initiates back-to-back messages to other User
User A's UI becomes unresponsive and eventually the app crashes.
Stack Trace Analysis:
The crash occurs on the main thread, which appears to be blocked waiting for a condition in the keyboard handling system. The thread is stuck in [UIKeyboardTaskQueue _lockWhenReadyForMainThread] and related methods, suggesting an issue with keyboard-related operations during the messaging process.
Crash Tag
Exception Type: EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: FRONTBOARD 2343432205
<RBSTerminateContext| domain:10 code:0x8BADF00D explanation:scene-update watchdog transgression: app<com.msikodiak.eptt(AD934F8A-DF57-4B75-BE73-8CF1A9A8F856)>:301 exhausted real (wall clock) time allowance of 10.00 seconds
ProcessVisibility: Foreground
ProcessState: Running
WatchdogEvent: scene-update
WatchdogVisibility: Background
WatchdogCPUStatistics: (
"Elapsed total CPU time (seconds): 6.390 (user 3.640, system 2.750), 11% CPU",
"Elapsed application CPU time (seconds): 0.020, 0% CPU"
)
ThermalInfo: (
"Thermal Level: 0",
"Thermal State: nominal"
) reportType:CrashLog maxTerminationResistance:Interactive>
Triggered by Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x1e773d438 __psynch_cvwait + 8
1 libsystem_pthread.dylib 0x2210bc328 _pthread_cond_wait + 1028
2 Foundation 0x1957d8a64 -[NSCondition waitUntilDate:] + 132
3 Foundation 0x1957d8888 -[NSConditionLock lockWhenCondition:beforeDate:] + 80
4 UIKitCore 0x1998f1238 -[UIKeyboardTaskQueue _lockWhenReadyForMainThread] + 456
5 UIKitCore 0x19a3d775c __59-[UIKeyboardImpl updateAutocorrectPrompt:executionContext:]_block_invoke_9 + 28
6 UIKitCore 0x19986b084 -[UIKeyboardTaskQueue lockWhenReadyForMainThread] + 168
7 UIKitCore 0x19a3f2994 -[UIKeyboardTaskQueue waitUntilTaskIsFinished:] + 148
8 UIKitCore 0x19a3f2ac4 -[UIKeyboardTaskQueue performSingleTask:breadcrumb:] + 132
9 UIKitCore 0x199e2f7e4 -[_UIKeyboardStateManager updateForChangedSelection] + 144
10 UIKitCore 0x199e24200 -[_UIKeyboardStateManager invalidateTextEntryContextForTextInput:] + 92
11 WebKit 0x1ad52fa54 WebKit::PageClientImpl::didProgrammaticallyClearFocusedElement(WebCore::ElementContext&&) + 40
12 WebKit 0x1ad55adcc WebKit::WebPageProxy::didProgrammaticallyClearFocusedElement(WebCore::ElementContext&&) + 136
13 WebKit 0x1acec74e8 WebKit::WebPageProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 18604
14 WebKit 0x1acd21184 IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&) + 236
15 WebKit 0x1ace449b8 WebKit::WebProcessProxy::dispatchMessage(IPC::Connection&, IPC::Decoder&) + 40
16 WebKit 0x1ace44228 WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 1764
17 WebKit 0x1acd1e904 IPC::Connection::dispatchMessage(***::UniqueRef<IPC::Decoder>) + 268
18 WebKit 0x1acd1e478 IPC::Connection::dispatchIncomingMessages() + 576
19 JavaScriptCore 0x1ae386b8c ***::RunLoop::performWork() + 524
20 JavaScriptCore 0x1ae386960 ***::RunLoop::performWork(void*) + 36
21 CoreFoundation 0x196badce4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
22 CoreFoundation 0x196badc78 __CFRunLoopDoSource0 + 172
23 CoreFoundation 0x196bac9fc __CFRunLoopDoSources0 + 232
24 CoreFoundation 0x196babc3c __CFRunLoopRun + 840
25 CoreFoundation 0x196bd0700 CFRunLoopRunSpecific + 572
26 GraphicsServices 0x1e3711190 GSEventRunModal + 168
27 UIKitCore 0x1997ee240 -[UIApplication _run] + 816
28 UIKitCore 0x1997ec470 UIApplicationMain + 336
29 Telstra PTT 0x1004d30c8 main + 56
30 dyld 0x1bd5d3ad8 start + 5964
We are currently developing a VoIP application that supports Local Push extention.
I would like to ask for your advice on how the extension works when the iPhone goes into sleep mode.
Our App are using GCD (Grand Central Dispatch) to perform periodic processing within the extension, creating a cycle by it.
[sample of an our source]
class LocalPushProvider: NEAppPushProvider {
let activeQueue: DispatchQueue = DispatchQueue(label: "com.myapp.LocalPushProvider.ActiveQueue", autoreleaseFrequency: .workItem)
var activeSchecule: Cancellable?
override func start(completionHandler: @escaping (Error?) -> Void) {
:
self.activeSchecule = self.activeQueue.schedule(
after: .init(.now() + .seconds(10)), // start schedule after 10sec
interval: .seconds(10) // interval 10sec
) {
self.activeTimerProc()
}
completionHandler(nil)
}
}
However In this App that we are confirming that when the iPhone goes into sleep mode, self.activeTimerProc() is not called at 10-second intervals, but is significantly delayed (approximately 30 to 180 seconds).
What factors could be causing the timer processing using GCD not to be executed at the specified interval when the iPhone is in sleep mode?
Also, please let us know if there are any implementation errors or points to note.
I apologize for bothering you during your busy schedule, but I would appreciate your response.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
PushKit
CallKit
Network Extension
Dispatch
Hi Team,
We intend to create a custom serial dispatch queue targetting a global queue.
let serialQueue = DispatchQueue(label: "corecomm.tallyworld.serial", target: DispatchQueue.global(qos: .default))
The documentation for DispatchQueue init does not show any minimum OS versions. BUT DispatchSerialQueue init does show iOS 17.0+ iPadOS 17.0+ Mac Catalyst macOS 14.0+ tvOS 17.0+ visionOS watchOS 10.0+.
Does that mean - I will not be able to create a custom serial dispatch queue below iOS 17?
I’m trying to enable Background Modes (specifically for audio, background fetch, remote notifications) in my iOS SwiftUI app, but I’m getting this error:
Provisioning profile “iOS Team Provisioning Profile: [my app]” doesn’t include the UIBackgroundModes entitlement.
On the developer website when I make the provision profile It doesnt give me the option to allow background modes.
I added it to the sign in capabilities seccion in X code and matched the bundle ID to the provision profile and certificate etc but it still runs this error because the provision profile doesnt have the entitlements..
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Entitlements
Provisioning Profiles
We are experiencing a crash in our application that only occurs on devices running iOS beta 26. It looks like a Beta problem.
The crash appears to be caused by an excessive number of open File Descriptors.
We identified this after noticing a series of crashes in different parts of the code each time the app was launched. Sometimes it would crash right at the beginning, when trying to load the Firebase plist file.
That’s when we noticed a log message saying “too many open files,” and upon further investigation, we found that an excessive number of File Descriptors were open in our app, right after the didFinishLaunching method of the AppDelegate.
We used the native Darwin library to log information about the FDs and collected the following:
func logFDs() {
var rlim = rlimit()
if getrlimit(RLIMIT_NOFILE, &rlim) == 0 {
print("FD LIMIT: soft: \(rlim.rlim_cur), hard: \(rlim.rlim_max)")
}
// Count open FDs before Firebase
let openFDsBefore = countOpenFileDescriptors()
print("Open file descriptors BEFORE Firebase.configure(): \(openFDsBefore)")
}
private func countOpenFileDescriptors() -> Int {
var count = 0
let maxFD = getdtablesize()
for fd in 0..<maxFD {
if fcntl(fd, F_GETFD) != -1 {
count += 1
}
}
return count
}
With this code, we obtained the following data:
On a device with iOS 26 Beta 1, 2, or 3:
FD LIMIT: soft: 256, hard: 9223372036854775807
Open file descriptors BEFORE Firebase.configure(): 256
On a device with iOS 18:
FD LIMIT: soft: 256, hard: 9223372036854775807
Open file descriptors BEFORE Firebase.configure(): 57
In the case of the device running iOS 26 beta, the app crashes when executing Firebase.configure() because it cannot open the plist file, even though it can be found at the correct path — meaning the OS locates it.
To confirm this was indeed the issue, we used the following code to close FDs before proceeding with Firebase configuration. By placing a breakpoint just before Firebase.configure() and running the following LLDB command:
expr -l c -- for (int fd = 180; fd < 256; fd++) { (int)close(fd); }
This released the FDs, allowing Firebase to proceed with its configuration as expected. However, the app would later crash again after hitting the soft limit of file descriptors once more.
Digging deeper, we used this code to try to identify which FDs were being opened and causing the soft limit to be exceeded:
func checkFDPath() {
var r = rlimit()
if getrlimit(RLIMIT_NOFILE, &r) == 0 {
print("FD LIMIT: soft: \(r.rlim_cur), hard: \(r.rlim_max)")
for fd in 0..<Int32(r.rlim_cur) {
var path = [CChar](repeating: 0, count: Int(PATH_MAX))
if fcntl(fd, F_GETPATH, &path) != -1 {
print(String(cString: path))
}
}
}
}
We ran this command at the very beginning of the didFinishLaunching method in the AppDelegate.
On iOS 26, the log repeatedly showed Cryptexes creating a massive number of FDs, such as:
/dev/null
/dev/ttys000
/dev/ttys000
/private/var/mobile/Containers/Data/Application/AEE414F2-7D6F-44DF-A6D9-92EDD1D2B014/Library/Application Support/DTX_8.191.1.1003.sqlite
/private/var/mobile/Containers/Data/Application/AEE414F2-7D6F-44DF-A6D9-92EDD1D2B014/Library/Caches/KSCrash/MyAppScheme/Data/ConsoleLog.txt
/private/var/mobile/Containers/Data/Application/AEE414F2-7D6F-44DF-A6D9-92EDD1D2B014/Library/HTTPStorages/mybundleId/httpstorages.sqlite
/private/var/mobile/Containers/Data/Application/AEE414F2-7D6F-44DF-A6D9-92EDD1D2B014/Library/HTTPStorages/mybundleId/httpstorages.sqlite-wal
/private/var/mobile/Containers/Data/Application/AEE414F2-7D6F-44DF-A6D9-92EDD1D2B014/Library/HTTPStorages/mybundleId/httpstorages.sqlite-shm
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.01
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.11
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.12
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.13
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.14
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.15
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.16
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.17
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.18
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.19
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.20
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.21
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.22
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.23
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.24
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.25
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.26
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.29
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.30
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.31
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.32
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.36
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.37
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.38
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.39
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.40
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e
…
This repeats itself a lot of times.
…
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.36
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.37
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.38
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.39
/private/preboot/Cryptexes/OS/System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.40
I am trying to create an app bundle with an xpc service. The main app creates a keychain item, and attempts to share (keychain access groups) with the xpc service it includes in its bundle. However, the xpc service always encounters a 'user interaction not allowed' error regardless of how I create the keychain item. kSecAttrAccessiblei is set to kSecAttrAccessibleWhenUnlockedThisDeviceOnly, the keychain access group is set for both the main app and the xpc service and in the provisioning profile. I've tried signing and notarizing.
Is it ever possible for an xpc service to access the keychain? This all on macos 15.5.
Hi, I'm working on an application on MacOS. It contains a port-forward feature on TCP protocol.
This application has no UI, but a local HTTP server where user can access to configure this application.
I found that my application always exit for unknown purpose after running in backgruond for minutes. I think this is about MacOS's background process controlling.
Source codes and PKG installers are here: https://github.com/burningtnt/Terracotta/actions/runs/16494390417
I have an application, it has main process and some child processes. As we want those child processes to have their own minimum sandbox privilege, not inheriting from parent process, we plan to use XPCService which uses a NSTask to launch those child processes, so those child processes can have its own sandbox privilege.
We plan to deliver the application to Mac App Store, so process mode is: the sandboxed main process builds connections to the unsandboxed XPCService, the unsandboxed XPCService launch those sandboxed child processes.
Can this process mode pass the Mac App Store rules? I see, there is a rule that all processes must be sandboxed, including XPCService. But I tested locally, the Application downloaded from Mac apple store also launches unsandboxed XPCService, like OneDrive.
Do you have any suggestions for my application scenario, sandboxed child processes having its own privilege not inheriting from parent?
I am new to building apps for MacOS using SwiftUI but built apps for iOS currently in the store.
I built an events app that stores a bunch of dates. The issue I have is that after X amount of time, the app needs to generate more events. In iOS I would use Background task to handle this, runs once daily etc.
After much research I am pointed to using a LaunchAgents with an Embedded Helper Tool https://developer.apple.com/documentation/Xcode/embedding-a-helper-tool-in-a-sandboxed-app
I am following this post: https://developer.apple.com/forums/thread/721737?answerId=739716022#739716022
I am stuck on setting up the plist file and clicking the button to try to add the launch item in simulator I get the following error:
did not register, error: Error Domain=SMAppServiceErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedFailureReason=Operation not permitted}
If this is the incorrect approach please let me know as I am stuck. Thanks.
I was experimenting with Service Management API and Xcode project from https://developer.apple.com/documentation/servicemanagement/updating-your-app-package-installer-to-use-the-new-service-management-api
and faced some issues with the API.
I replaced agent with XPC service and tried to re-register it.
Use case is a new app package installation with a newer service binary. In order to get the running service restarted with the new binary it's required to unregister old version and register new one. Otherwise the old version would be still running after app upgrade.
The problem is that register fails with "Operation not permitted" error after running unregister which seems to work fine.
Experiments with some delays (500ms) between unregister and register seem to help but it's a not a good solution to work around the problem.
I'm using open func unregister() async throws with description:
The completion handler will be invoked after the running process has been killed if successful or will be invoked whenever an error occurs. After the completion handler has been invoked it is safe to re-register the service.
Sample output with no 500ms sleep between unregister and register calls:
/Library/Application\ Support/YourDeveloperName/SMAppServiceSampleCode.app/Contents/MacOS/SMAppServiceSampleCode unregister && /Library/Application\ Support/YourDeveloperName/SMAppServiceSampleCode.app/Contents/MacOS/SMAppServiceSampleCode register
Successfully unregistered LaunchDaemon(com.xpc.example.service.plist)
Unable to register LaunchDaemon(com.xpc.example.service.plist): Error Domain=SMAppServiceErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedFailureReason=Operation not permitted}
In fact it doesn't seem to be safe to re-register. Any explanation would much appreciated!
=====================================================
Side issue #2: I tried to add a similar helper executable as in the original project with register/unregister and put it inside the same app bundle but at a different location like Contents/Helpers/ folder instead of Contents/MacOS. And it always fails with this error:
Error Domain=SMAppServiceErrorDomain Code=3 "Codesigning failure loading plist: com.okta.service.osquery code: -67028" UserInfo={NSLocalizedFailureReason=Codesigning failure loading plist: com.okta.service.osquery code: -67028}
When I moved the helper binary to Contents/MacOS/ folder along with the main app executable it starts working fine again. Other folders like Resources/XPCServices also don't work.
Is it a hard requirement for an executable to be located inside main Contents/MacOS folder in order to be able to call SMAppService register/unregister APIs? I haven't found any documentation regarding this requirement.
Thanks,
Pavel
Hey,
I have a user script that I have set up to run daily with launchd, the launchd logs indicate that the script is started but it's almost immediately exited with status 0. The odd thing is that it doesn't say that the script was killed or stopped in anyway, even though that is what seems to happen.
2024-12-04 14:15:04.970214 (gui/501/com.me.test) <Notice>: internal event: WILL_SPAWN, code = 0 2024-12-04 14:15:04.970320 (gui/501/com.me.test) <Notice>: service state: spawn scheduled 2024-12-04 14:15:04.970325 (gui/501/com.me.test) <Notice>: service state: spawning 2024-12-04 14:15:04.970431 (gui/501/com.me.test) <Notice>: launching: xpc event 2024-12-04 14:15:04.972067 (gui/501/com.me.test [26446]) <Notice>: xpcproxy spawned with pid 26446 2024-12-04 14:15:04.972096 (gui/501/com.me.test [26446]) <Notice>: internal event: SPAWNED, code = 0 2024-12-04 14:15:04.972107 (gui/501/com.me.test [26446]) <Notice>: service state: xpcproxy 2024-12-04 14:15:04.972160 (gui/501/com.me.test [26446]) <Notice>: internal event: SOURCE_ATTACH, code = 0 2024-12-04 14:15:04.998157 (gui/501/com.me.test [26446]) <Notice>: service state: running 2024-12-04 14:15:04.998180 (gui/501/com.me.test [26446]) <Notice>: internal event: INIT, code = 0 2024-12-04 14:15:04.998199 (gui/501/com.me.test [26446]) <Notice>: Successfully spawned shell_wrapper.sh[26446] because xpc event 2024-12-04 14:15:05.217482 (gui/501/com.me.test [26446]) <Notice>: exited due to exit(0), ran for 246ms 2024-12-04 14:15:05.217494 (gui/501/com.me.test [26446]) <Notice>: service state: exited 2024-12-04 14:15:05.217502 (gui/501/com.me.test [26446]) <Notice>: internal event: EXITED, code = 0 2024-12-04 14:15:05.217506 (gui/501 [100003]) <Notice>: service inactive: com.me.test 2024-12-04 14:15:05.217523 (gui/501/com.me.test [26446]) <Notice>: service state: not running
In the script itself I log at the end to indicate that it finished successfully, when ran with launchd I never reach this point however. The script also do two network requests and make a pause for between 5-10 seconds with time.sleep(paus) (python script). However the launchd log indicates that the script finished in 246ms.
Not sure what is going on, the script itself does not require any privileges above a normal user. I have tried running the script directly, and it works as expected. I have also tried evoking the script from launchd explicitly with: launchctl kickstart which starts the job but gives the same result as the scheduled job, except the log now says: `launching: non-ipc demand' instead.
I have also tried to remove the networking requests and replace them by reading data from a file without any sleep, no difference in outcome though.
I have generated the launchd plist file using Lingon.app and it's placed in ~/Library/LaunchAgents
Not sure what more information I can provide, but need some suggestion on how I can proceed help solving this.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
We are building a 'server' application that can either run as a daemon or can run in background without showing any GUI. Basically, the end user can either configure this to run as a daemon so that it can be tied to the user's session or will launch the process which user will start and quit as needed.
I wanted to understand what is the recommended mechanism for such an application from Apple -
Should this application be built as a macOS Bundle ? Apple documentation also says that we should not daemonize the process by calling fork. Hence if we create a unix-style executable, will I not need to fork to make it run in a detached state when I launch the executable via double-click ? [Reference Link]
Is it fine to have an application on macOS which is a bundle but does not show any UI when launched by double click on the app-icon or via 'open'? While we have been able to achieve this by using NSApplicationMain and not showing the UI, was wondering if using CFRunLoop is best for this case as it is a non-gui application.
If we can get the right documentation link or recommendations on how we should build such an application which can run in a non-gui mode and also in a daemonized manner, it will help us.
Should the application be always built as a macos bundle or should it be a unix-style executable to support both the cases - by the same application/product and how should we look at the distribution of such applications.
Hi,
I have a sandboxed app with a bundled sandboxed XPC service. When it’s launched, the XPC service registers a repeating XPC activity with the system. The activity’s handler block does get called regularly like I’d expect, but it stops being called once the main app terminates.
What’s the recommended way to fix this issue? Could I have a bundled XPC service double as a launch agent, or would that cause other problems?
For some reason, after invoking an unrelated dlclose() call to unload any .dylib that had previously been loaded via dlopen(..., RTLD_NOW), the subsequent call to task_info(mach_task_self(), TASK_DYLD_INFO, ...) syscall returns unexpected structure in dyld_uuid_info image_infos->uuidArray, that, while it seems to represent an array of struct dyld_uuid_info elements, there is only 1 such element (dyld_all_image_infos *infos->uuidArrayCount == 1) and the app crashes when trying to access dyld_uuid_info image->imageLoadAddress->magic, as image->imageLoadAddress doesn't seem to represent a valid struct mach_header structure address (although it looks like a normal pointer within the process address space. What does it point to?).
This reproduces on macOS 15.4.1 (24E263)
Could you please confirm that this is a bug in the specified OS build, or point to incorrect usage of the task_info() API?
Attaching the C++ file that reproduces the issue to this email message
It needs to be built on macOS 15.4.1 (24E263) via Xcode or just a command line clang++ compiler. It may crash or return garbage, depending on memory layout, but on this macOS build it doesn’t return a correct feedfacf magic number for the struct mach_header structure.
Thank you
Feedback Assistant reference: FB18431345
//On `macOS 15.4.1 (24E263)` create a C++ application (for example, in Xcode), with the following contents. Note, that this application should crash on this macOS build. It will not crash, however, if you either:
//1. Comment out `dlclose()` call
//2. Change the order of the `performDlOpenDlClose()` and `performTaskInfoSyscall()` functions calls (first performTaskInfoSyscall() then performDlOpenDlClose()).
#include <iostream>
#include <dlfcn.h>
#include <mach/mach.h>
#include <mach-o/dyld_images.h>
#include <mach-o/loader.h>
void performDlOpenDlClose() {
printf("dlopen/dlclose function\n");
printf("Note: please adjust the path below to any real dylib on your system, if the path below doesn't exist!\n");
std::string path = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libswiftDemangle.dylib";
printf("Dylib to open: %s\n", path.c_str());
void* handle = ::dlopen(path.c_str(), RTLD_NOW);
if(handle) {
::dlclose(handle);
} else {
printf("Error: %s\n", dlerror());
}
}
void performTaskInfoSyscall() {
printf("Making a task_info() syscall\n");
printf("\033[34mSource File: %s\033[0m\n", __FILE__);
task_t task = mach_task_self();
struct task_dyld_info dyld_info;
mach_msg_type_number_t size = TASK_DYLD_INFO_COUNT;
kern_return_t kr = task_info(task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &size);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "task_info failed: %s\n", mach_error_string(kr));
}
const struct dyld_all_image_infos* infos =
(const struct dyld_all_image_infos*)dyld_info.all_image_info_addr;
printf("version: %d, infos->infoArrayCount: %d\n", infos->version, infos->infoArrayCount);
for(uint32_t i=0; i<infos->infoArrayCount; i++) {
dyld_image_info image = infos->infoArray[i];
const struct mach_header* header = image.imageLoadAddress;
printf("%d ", i);
printf("%p ", (void*)image.imageLoadAddress);
printf("(%x) ", header->magic);
printf("%s\n", image.imageFilePath);
fflush(stdout);
}
printf("\n\n");
printf("infos->uuidArrayCount: %lu\n", infos->uuidArrayCount);
for(uint32_t i=0; i<infos->uuidArrayCount; i++) {
dyld_uuid_info image = infos->uuidArray[i];
const struct mach_header* header = image.imageLoadAddress;
printf("%d ", i);
printf("%p ", (void*)image.imageLoadAddress);
printf("(%x)\n", header->magic);
fflush(stdout);
}
printf("task_info() syscall result processing is completed\n\n");
}
int main(int argc, const char * argv[]) {
performDlOpenDlClose();
performTaskInfoSyscall();
return 0;
}
when we use raise in GCD, the signal handler is executed asynchronously, whereas in pthread, it is executed synchronously as expected.
example:
#include <Foundation/Foundation.h>
#include <pthread/pthread.h>
static void HandleSignal(int sigNum, siginfo_t* signalInfo, void* userContext) {
printf("handle signal %d\n", sigNum);
printf("begin sleep\n");
sleep(3);
printf("end sleep\n");
}
void InstallSignal(void) {
static const int g_fatalSignals[] =
{
SIGABRT,
SIGBUS,
SIGFPE,
SIGILL,
SIGPIPE,
SIGSEGV,
SIGSYS,
SIGTRAP,
};
int fatalSignalsCount = sizeof(g_fatalSignals) / sizeof(int);
struct sigaction action = {{0}};
action.sa_flags = SA_SIGINFO | SA_ONSTACK;
#if defined(__LP64__)
action.sa_flags |= SA_64REGSET;
#endif
sigemptyset(&action.sa_mask);
action.sa_sigaction = &HandleSignal;
struct sigaction pre_sa;
for(int i = 0; i < fatalSignalsCount; i++) {
int sigResult = sigaction(g_fatalSignals[i], &action, &pre_sa);
}
}
void* RaiseAbort(void *userdata) {
raise(SIGABRT);
printf("signal handler has finished\n");
return NULL;
}
int main(int argc, const char * argv[]) {
InstallSignal();
dispatch_async(dispatch_get_global_queue(0, 0), ^{
raise(SIGABRT);
// abort(); // abort() is ok
RaiseAbort(nullptr);
});
// pthread is ok
// pthread_t tid;
// int ret = pthread_create(&tid, NULL, RaiseAbort, NULL);
// if (ret != 0) {
// fprintf(stderr, "create thread failed\n");
// return EXIT_FAILURE;
// }
[[NSRunLoop mainRunLoop] run];
return 0;
}
console log:
signal handler has finished
handle signal 6
begin sleep
end sleep
I have been experimenting with the BGContinuedProcessingTask API recently (and published sample code for it https://github.com/infinitepower18/BGContinuedProcessingTaskDemo)
I have noticed that if I lock the phone, the code that runs as part of the task stops executing. My sample code simply updates the progress each second until it gets to 100, so it should be completed in 1 minute 40 seconds. However, after locking the phone and checking the lock screen a few seconds later the progress indicator was in the same position as before I locked it.
If I leave the phone locked for several minutes and check the lock screen the live activity says "Task failed".
I haven't seen anything in the documentation regarding execution of tasks while the phone is locked. So I'm a bit confused if I encountered an iOS bug here?
Testing Environment:
iOS: 26.0 Beta 7
Xcode: Beta 6
Description:
We are implementing the new BGContinuedProcessingTask API introduced in iOS 26. We have followed the official documentation and WWDC session guidance to configure our project.
The Background Modes (processing) and Background GPU Access capabilities have been added in Xcode.
The com.apple.developer.background-tasks.continued-processing.gpu entitlement is present and set to in the .entitlements file.
The provisioning profile details viewed within Xcode explicitly show that the "Background GPU Access" capability and the corresponding entitlement are included.
Despite this correct configuration, when running the app on supported hardware (iPhone 16 Pro), a call to BGTaskScheduler.supportedResources.contains(.gpu) consistently returns false.
This prevents us from setting request.requiredResources = .gpu. As a result, when the BGContinuedProcessingTask starts without the GPU resource flag, our internal Metal-based exporter attempts to access the GPU and is terminated by the system, throwing an IOGPUMetalError: Insufficient Permission (to submit GPU work from background).
We have performed extensive debugging, including a full reset of the provisioning profile (removing/re-adding capabilities, toggling automatic signing, cleaning build folders, and reinstalling the app), but the issue persists. This strongly suggests a bug in the iOS 26 beta where the runtime is failing to correctly validate a valid entitlement.
Additionally, we've observed inconsistent behavior across devices. On an A16-based iPad, the task submits successfully (BGTaskScheduler.submit does not throw an error), but the launch handler is never invoked by the system. On the iPhone 16 Pro, the handler is invoked, but we encounter the supportedResources issue described above. This leads us to ask for clarification on the exact hardware requirements for this feature. We hypothesize that it may be limited to devices that support Apple Intelligence (A17 Pro and newer). Could you please confirm this and provide official documentation on the device support criteria?
Steps to Reproduce:
Create a new Xcode project.
In Signing & Capabilities, add "Background Modes" (with "Background processing" checked) and "Background GPU Access".
Add a permitted identifier (e.g., "com.company.test.*") to BGTaskSchedulerPermittedIdentifiers in Info.plist.
In application(_:didFinishLaunchingWithOptions:) or a ViewController's viewDidLoad, log the result of BGTaskScheduler.shared.supportedResources.contains(.gpu).
Build and run on a physical, supported device (e.g., iPhone 16 Pro).
Expected Results:
The log should indicate that BGTaskScheduler.shared.supportedResources.contains(.gpu) returns true.
Actual Results:
The log shows that BGTaskScheduler.shared.supportedResources.contains(.gpu) returns false.
On MacOS 26 Tahoe, we are getting a background warning message stating, “App is running in the background…”
Is this expected behavior on the new OS?
Thanks
Asutos
Topic:
App & System Services
SubTopic:
Processes & Concurrency
The following code worked as expected on iOS 26 RC, but it no longer works on the official release of iOS 26.
Is there something I need to change in order to make it work on the official version?
Registration
BGTaskScheduler.shared.register(
forTaskWithIdentifier: taskIdentifier,
using: nil
) { task in
//////////////////////////////////////////////////////////////////////
// This closure is not called on the official release of iOS 26
//////////////////////////////////////////////////////////////////////
let task = task as! BGContinuedProcessingTask
var shouldContinue = true
task.expirationHandler = {
shouldContinue = false
}
task.progress.totalUnitCount = 100
task.progress.completedUnitCount = 0
while shouldContinue {
sleep(1)
task.progress.completedUnitCount += 1
task.updateTitle("\(task.progress.completedUnitCount) / \(task.progress.totalUnitCount)", subtitle: "any subtitle")
if task.progress.completedUnitCount == task.progress.totalUnitCount {
break
}
}
let completed = task.progress.completedUnitCount >= task.progress.totalUnitCount
if completed {
task.updateTitle("Completed", subtitle: "")
}
task.setTaskCompleted(success: completed)
}
Request
let request = BGContinuedProcessingTaskRequest(
identifier: taskIdentifier,
title: "any title",
subtitle: "any subtitle",
)
request.strategy = .queue
try BGTaskScheduler.shared.submit(request)
Sample project code:
https://github.com/HikaruSato/ExampleBackgroundProcess