Can I call NSApplicationLoad from a launch daemon?

75 views Asked by At

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?

1

There are 1 answers

0
pmdj On

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.)