To receive some notifications (for instance, CGDisplayRegisterReconfigurationCallback) from my launch daemon (written in C++ for macOS) I need to call NSApplicationLoad
before I call CFRunLoopRun();
(as described here). But once in a while my daemon received SIGABRT signal with the following callstack in the crash file:
Application Specific Backtrace 0:
0 CoreFoundation 0x0000000199574418 __exceptionPreprocess + 176
1 libobjc.A.dylib 0x00000001990beea8 objc_exception_throw + 60
2 CoreFoundation 0x0000000199616c3c -[NSObject(NSObject) __retain_OA] + 0
3 CoreFoundation 0x00000001994da6b0 ___forwarding___ + 1600
4 CoreFoundation 0x00000001994d9fb0 _CF_forwarding_prep_0 + 96
5 CoreFoundation 0x0000000199488000 CFURLCopyAbsoluteURL + 72
6 CoreFoundation 0x00000001994b72f0 _CFBundleCopyLProjDirectoriesForURL + 76
7 CoreFoundation 0x00000001995de070 _copyBundleLocalizationsFromResources + 348
8 CoreFoundation 0x00000001995dda00 _CFBundleCopyBundleLocalizations + 140
9 CoreFoundation 0x00000001994b662c _CFLocaleCopyCurrentGuts + 792
10 CoreFoundation 0x00000001994b62e8 +[NSLocale currentLocale] + 16
11 Foundation 0x000000019a3aabfc -[NSUserDefaults(NSUserDefaults) init] + 1136
12 Foundation 0x000000019a3aa740 +[NSUserDefaults(NSUserDefaults) standardUserDefaults] + 64
13 AppKit 0x000000019c71b0c8 +[NSApplication initialize] + 88
14 libobjc.A.dylib 0x00000001990aec98 CALLING_SOME_+initialize_METHOD + 24
15 libobjc.A.dylib 0x00000001990ae980 initializeNonMetaClass + 608
16 libobjc.A.dylib 0x00000001990c96ac _ZL24initializeAndMaybeRelockP10objc_classP11objc_objectR12locker_mixinIN9lockdebug10lock_mixinI16objc_lock_base_tEEEb + 184
17 libobjc.A.dylib 0x00000001990ae26c lookUpImpOrForward + 1052
18 libobjc.A.dylib 0x00000001990adb64 _objc_msgSend_uncached + 68
19 AppKit 0x000000019c96fd90 NSApplicationLoad + 68
20 MyDaemon 0x0000000102e5ec00 _ZN4CSvc3RunEiPPKc + 6256
21 MyDaemon 0x0000000102e83f4c main + 92
22 dyld 0x00000001990efe50 start + 2544
and:
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x1993e3224 __pthread_kill + 8
1 libsystem_pthread.dylib 0x199419cec pthread_kill + 288
2 libsystem_c.dylib 0x199353354 __abort + 128
3 libsystem_c.dylib 0x1993532d4 abort + 192
4 libc++abi.dylib 0x1993d3b18 abort_message + 132
5 libc++abi.dylib 0x1993c3a0c demangling_terminate_handler() + 336
6 libobjc.A.dylib 0x1990c7764 _objc_terminate() + 144
7 libc++abi.dylib 0x1993d2eb4 std::__terminate(void (*)()) + 20
8 libc++abi.dylib 0x1993d5ecc __cxa_rethrow + 148
9 libobjc.A.dylib 0x1990d9544 objc_exception_rethrow + 44
10 libobjc.A.dylib 0x1990ae9c0 initializeNonMetaClass + 672
11 libobjc.A.dylib 0x1990c96ac initializeAndMaybeRelock(objc_class*, objc_object*, locker_mixin<lockdebug::lock_mixin<objc_lock_base_t> >&, bool) + 184
12 libobjc.A.dylib 0x1990ae26c lookUpImpOrForward + 1052
13 libobjc.A.dylib 0x1990adb64 _objc_msgSend_uncached + 68
14 AppKit 0x19c96fd90 NSApplicationLoad + 68
15 MyDaemon 0x102e5ec00 My::Run(int, char const**) + 6256 (CSvc.cpp:601)
16 MyDaemon 0x102e83f4c main + 92 (main.cpp:47)
17 dyld 0x1990efe50 start + 2544
Can I call NSApplicationLoad
from a launch daemon?
And if not, then how do I get the CGDisplayRegisterReconfigurationCallback
notification in it?
You can't call
NSApplicationLoad
from a launch daemon, and you can't receive Core Graphics events.If you think about this in more detail, it becomes clear that this also doesn't really make any sense. Launch daemons start up and shut down entirely independently from windowing/login sessions. So even if you managed to obtain a connection to a running Core Graphics session representing a logged in user's session, if that user logged out, the connection would go stale.
You can obtain Core Graphics connections in launch agents, whose lifetimes are tied to various session contexts. You can register a launch agent which will be brought up with every windowing session and terminated when such a session ends. You can make it register for any events you wish to receive, and connect to your launch daemon via XPC to forward those events to it. I recommend you look into the
LimitLoadToSessionType
property if you're also interested in windowing events on the login screen itself. (There are some good Q&A on Stack Overflow on launch agent session types, including this one.)