Is there a way to ensure a kernel extension in the Auxiliary Kernel Collection loads (and runs its start
routines) before launchd
?
I'm emitting logs via os_log_t
created with an os_log_create
(custom subsystem/category) in both my KMOD's start
function and the IOService::start()
function. Those messages-- which both say "I've been run"-- inconsistently show up in log show --predicate 'subsystem == "com.bluefalconhd.pandora"' --last boot
, which makes me think they are running very early. However, I also record timestamps (using mach_absolute_time
, etc.) and expose them to user space through an IOExternalMethod
. The results (for the most recent boot):
hayes@fortis Pandora/tests main % build/pdtest
Pandora Metadata:
kmod_start_time:
Time: 2025-07-22 14:11:32.233
Mach time: 245612546
Nanos since boot: 10233856083 (10.23 seconds)
io_service_start_time:
Time: 2025-07-22 14:11:32.233
Mach time: 245613641
Nanos since boot: 10233901708 (10.23 seconds)
user_client_init_time:
Time: 2025-07-22 14:21:42.561
Mach time: 14893478355
Nanos since boot: 620561598125 (620.56 seconds)
hayes@fortis Pandora/tests main % ps -p 1 -o lstart=
Tue Jul 22 14:11:27 2025
Everything in the kernel extension appears to be loading after launchd
(PID 1) starts. Also, the kext isn't doing anything crazy which could cause that kind of delay.
For reference, here's the Info.plist:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>Pandora</string>
<key>CFBundleIdentifier</key>
<string>com.bluefalconhd.Pandora</string>
<key>CFBundleName</key>
<string>Pandora</string>
<key>CFBundlePackageType</key>
<string>KEXT</string>
<key>CFBundleVersion</key>
<string>1.0.7</string>
<key>IOKitPersonalities</key>
<dict>
<key>Pandora</key>
<dict>
<key>CFBundleIdentifier</key>
<string>com.bluefalconhd.Pandora</string>
<key>IOClass</key>
<string>Pandora</string>
<key>IOMatchCategory</key>
<string>Pandora</string>
<key>IOProviderClass</key>
<string>IOResources</string>
<key>IOResourceMatch</key>
<string>IOKit</string>
<key>IOUserClientClass</key>
<string>PandoraUserClient</string>
</dict>
</dict>
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.kpi.dsep</key>
<string>24.2.0</string>
<key>com.apple.kpi.iokit</key>
<string>24.2.0</string>
<key>com.apple.kpi.libkern</key>
<string>24.2.0</string>
<key>com.apple.kpi.mach</key>
<string>24.2.0</string>
</dict>
</dict>
</plist>
My questions are:
- A. Why don't the early logs (from
KMOD
's start function andIOService::start
) consistently appear in the unified log, while logs later inIOExternalMethod
s do? - B. How can I force this kext to load earlier-- ideally before
launchd
?
Thanks in advance for any guidance!