Kernel-level mechanisms and interactions

While backgroundtaskmanagementd mostly operates in user-space, it leverages kernel interfaces to do its job.

FSEvents (File System Events)

The daemon uses the kernel’s FSEvents facility to know when launchd plist files appear or change. The smd LaunchDaemon is configured with a special LaunchEvents dictionary that ties the FSEvents stream to an XPC notification (com.apple.xpc.smd.WatchPaths) delivered to smd. This is a relatively new launchd feature where the kernel can trigger a user-space event when certain paths are modified. In this case, the kernel informs smd of changes in any of the watched directories (like /Library/LaunchAgents, ~/Library/LaunchAgents, etc.), and smd in turn informs BTM. This mechanism ensures kernel-level file changes (like an attacker dropping a plist) cannot bypass detection; as soon as the file is created, an event is fired. backgroundtaskmanagementd registers for those via smd, rather than polling the filesystem. The FSEvents stream runs with high priority in the kernel, meaning BTM will know about a persistence file even if it’s added outside of normal install processes.

Launchd & XPC (Mach Interfaces)

Launchd itself is part of user-space, but it interfaces with the kernel for process spawning and with XPC for service management. BTM’s coordination with launchd happens through Mach services. For example, when BTM or smd wants to stop a launchd job (say, user disabled it), it might call the launchctl APIs (which talk to launchd via Mach port messages). Launchd then uses kernel calls to actually spawn or kill processes. BTM doesn’t directly call the kernel to manage processes; it entrusts launchd to handle that.

There is also a Mach bootstrap namespace aspect: items launched via SMAppService might be in a per-user bootstrap namespace. BTM ensures that those helpers are registered in the correct domain (login session vs system) by communicating with launchd.

Power management (IOKit)

There isn’t much evidence that backgroundtaskmanagementd directly uses IOKit power assertions or power notifications. The tasks it manages are generally long-lived agents/daemons which launch at login or boot and remain running. MacOS’s power management (sleep/wake or “App Nap”) could indirectly affect background apps, but that’s handled by separate systems (e.g., AppNap is managed by the OS on a per-process basis if they lack user activity, and daemons can opt into power assertions themselves). backgroundtaskmanagementd may listen for system sleep or user logout events simply to possibly defer notifications or update its records, but no specific IOKit dependency is documented. It’s primarily concerned with launch policy, not scheduling tasks during sleep or such. (This contrasts with iOS’s background task scheduler which works with the kernel to wake apps – on macOS, if an app needs periodic background activity, it would use NSBackgroundActivityScheduler or similar, which is outside BTM’s scope.) In short, IOKit involvement is minimal: aside from normal macOS daemon behavior (receiving a system shutdown or reboot signal to possibly save state), BTMd doesn’t, for example, hold IOPMAssertions. One could consider the possibility that backgroundtaskmanagementd might use IOKit’s “dark wake” to schedule some maintenance (macOS does run some background tasks during Power Nap), but Apple has separate daemons for Power Nap tasks. BTM is more about controlling persistence and launch, not actively running tasks on a timer.

Jetsam / memory pressure

The term “jetsam” comes from iOS, referring to the kernel memory-pressure killing of background apps. On macOS, low-memory termination exists (the kernel will terminate processes if memory is critically low), but it’s less frequent on desktops. backgroundtaskmanagementd itself does not manage memory or kill tasks. However, by categorizing processes appropriately, the system can treat background tasks with a lower priority. For instance, processes launched as “background” (without UI) may receive a lower quality-of-service (QoS) class or be marked as non-interactive. On Apple Silicon Macs (which share architectural features with iOS), processes have a memorystatus category and priority. It’s possible that launchd/BTM assigns background daemons a lower jetsam priority, meaning if the system is under extreme memory pressure, those might be first to terminate. But this is speculative; Apple hasn’t stated that BTM enforces any jetsam policy. We do know that RunningBoard, the iOS daemon that enforces app lifecycle and jetsam, is present on macOS for iOS app compatibility, but macOS native processes are not generally subject to the same strict memory killing as iOS apps. So jetsam interactions are likely limited to the normal kernel behavior; BTM doesn’t directly interface with the jetsam subsystem.

Endpoint Security (ES) subsystem

Perhaps the most significant kernel interaction of backgroundtaskmanagementd is through the Endpoint Security framework. Apple extended ES in macOS 13 to include new event types for background task management. backgroundtaskmanagementd is entitled to submit ES events of type BTM_LAUNCH_ITEM_ADD and BTM_LAUNCH_ITEM_REMOVE. In fact, backgroundtaskmanagementd is linked against a private library (libEndpointSecuritySystem.dylib) that allows it to send these notifications to the ES client(s) in kernel. When BTM registers a new item, it calls an internal function (essentially _ess_notify_btm_launch_item_add) which causes the kernel’s ES module to broadcast an event to any security software subscribed. The event includes details: the instigator process (for example, the process that attempted persistence – often smd or the app that called SMAppService), the associated app (if the launch item is tied to an app bundle), and the item details (type of item: agent vs daemon, its label, and the file URL). For instance, an ES log captured by Wardle shows: Event: 'ES_EVENT_TYPE_NOTIFY_BTM_LAUNCH_ITEM_ADD' Type: ES_BTM_ITEM_TYPE_AGENT; Instigator: /usr/libexec/smd; Agent URL: ~/Library/LaunchAgents/com.apple.softwareupdate.plist. This was a real-world malware (OSX.DazzleSpy) persisting a LaunchAgent – BTM raised an ES alert flagging that smd (on behalf of something) added a new agent plist in the user’s LaunchAgents. Such events are invaluable for security monitoring, as they provide a guaranteed kernel-validated signal that persistence was added. Apple guarantees that if the ES event didn’t fire, the persistence didn’t happen (or the attacker completely bypassed BTM, which is rare without root). Initially, Apple’s implementation had a bug: the BTM remove event was not delivered to ES clients properly (so security tools wouldn’t get notified if an item was removed or disabled). Wardle reported this in early Ventura and Apple later fixed the ES removal event in a patch, improving the reliability of monitoring. In summary, through Endpoint Security, backgroundtaskmanagementd extends its reach into the kernel’s security layer, ensuring that both the user and security software are alerted to new persistent background tasks. (This is complementary to the user-facing notification; ES events are for programs like antivirus or enterprise monitors, whereas the Notification Center alert is for the human user.)

In effect, backgroundtaskmanagementd straddles the line between user-space and kernel-space: it operates as a user-space policy daemon but leverages kernel features (FSEvents, EndpointSecurity) to obtain input and produce outputs. It does not have a kernel extension of its own; instead, it relies on existing kernel subsystems. By design, Apple kept all BTM logic in user-space (making it easier to update and patch), using the kernel only as a sensor (file events) and notifier (ES events). This design also means BTM can be updated in point releases without needing kernel changes, except for adding new ES event types or similar in major releases.