macOS daemons and agents
UNIX-based operating systems have daemons or programs that run as background processes in the system context (eg named - the Internet Domain Name Server which is a daemon responsible for resolving domain name queries). Daemons are therefore better described as system background processes and should not have a graphical user interface. They are system-wide background processes of which there is only one instance for all clients.
Agents are very similar to daemons in that they are both programs that run as background processes, but in the case of agents they are not running in the system context but in the context of an interactive user's session. Agents are therefore better described as user background processes and may have a graphical user interface or communicate with the user through the macOS system menu bar (eg temperature monitors generally display the status in the system menu bar). They are per-user background processes.
Daemons and agents are each useful in their own right, but each has its own specific use cases. jobs that rely on system-level access should be run as daemons in the system context and jobs that do not require system-level access should be run as agents in the user's context.
Note: in the rest of this article the generic term daemon will be used to refer to both daemons and agents unless required otherwise by the context.
launchd is the macOS system-wide and per-user daemon manager which is started by the kernel during the system boot process. It manages processes, both for the system as a whole and for individual users. launchd provides the following benefits to daemon developers:
- Simplifies the process of making a daemon by handling many of the standard housekeeping chores normally associated with launching a daemon.
- Provides system administrators with a central place to manage daemons on the system.
- Supports inetd-style daemons.
- Eliminates the primary reason for running daemons as root. Because launchd runs as root, it can create low-numbered TCP/IP listen sockets and hand them off to the daemon.
- Simplifies error handling and dependency management for inter-daemon communication. As daemons can be launched on demand, communication requests do not fail if the daemon is not launched. They are simply delayed until the daemon can launch and process them.
The launchd startup process
After the system is booted and the kernel is running, launchd is run to finish the system initialization. As part of that initialization, it goes through the following steps:
- Loads the parameters for each launch-on-demand system-level daemon from the property list files found in /System/Library/LaunchDaemons/ and /Library/LaunchDaemons/.
- Registers the sockets and file descriptors requested by those daemons.
- Launches any daemons that requested to be running all the time.
- As requests for a particular service arrive, it launches the corresponding daemon and passes the request to it.
- When the system shuts down, it sends a SIGTERM signal to all of the daemons that it started.
The process for per-user agents is similar. When a user logs in, a per-user launchd is started. It does the following:
- Loads the parameters for each launch-on-demand user agent from the property list files found in /System/Library/LaunchAgents/, /Library/LaunchAgents/, and the user’s individual ~/Library/LaunchAgents/ directory.
- Registers the sockets and file descriptors requested by those user agents.
- Launches any user agents that requested to be running all the time.
- As requests for a particular service arrive, it launches the corresponding user agent and passes the request to it.
- When the user logs out, it sends a SIGTERM signal to all of the user agents that it started.
As launchd registers the sockets and file descriptors used by all daemons before it launches any of them, daemons can be launched in any order. If a request comes in for a daemon that is not yet running, the requesting process is suspended until the target daemon finishes launching and responds.
If a daemon does not receive any requests over a specific period of time, it can choose to shut itself down and release the resources it holds. When this happens, launchd monitors the shutdown and makes a note to launch the daemon again when future requests arrive.
launchctl is the primary interface to launchd which, among other things, allows the administrator or user to load or unload daemons or agents. Where possible, it is preferred that background jobs are launched on demand, based on criteria specified in their respective property list files.
Some of the useful commands available include:
|launchctl list||List loaded jobs|
|launchctl list <LABEL>||List information about this loaded job from its .plist file.|
|launchctl load /Library/LaunchDaemons/<LABEL>.plist||Load and start a job (system daemon) that is not disabled.|
|launchctl load -w /Library/LaunchDaemons/<LABEL>.plist||Load, start and mark a job as not disabled (system daemon). Job restarts on next reboot.|
|launchctl unload /Library/LaunchDaemons/<LABEL>.plist||Unload and stop a job (system daemon). Job restarts on next boot.|
|launchctl unload -w /Library/LaunchDaemons/<LABEL>.plist||Unload, stop and disable a job (system daemon). Job does not restart on next reboot.|
|launchctl start <LABEL>||Start a loaded job. Useful when debugging.|
|launchctl stop <LABEL>||Stop a loaded job. Job may restart immediately if configured to keep running.|
|launchctl restart <LABEL>||Restart a loaded job.|
Note: The commands listed above, while documented as "legacy", are simpler to use than the more complicated replacement commands. For the full details, open an Application > Utilities > Terminal and type man launchctl at the prompt to access the UNIX manual page.
Types of background processes
There are four types of background processes in macOS. To select the appropriate type of background process, consider the following:
- Whether it does something for the currently logged in user or for all users.
- Whether it will be used by single application or by multiple applications.
- Whether it ever needs to display a user interface or launch a GUI application.
|Type||Managed by launchd?||Runs in||Can present UI?|
|Login item||No*||Per user context||Yes|
|XPC service||Yes||Per user context||No|
(Except in a very limited way using IOSurface)
|Launch Daemon||Yes||System-wide context||No|
|Launch Agent||Yes||Per user context||Best practice: Not recommended|
* Login items are started by the per-user instance of launchd, but it does not take any actions to manage them.
Creating a launchd property list file
To run your daemon under launchd, you must provide a configuration property list file for it. This file contains information about your daemon, including the list of sockets or file descriptors it uses to process requests. Specifying this information in a property list file lets launchd register the corresponding file descriptors and launch your daemon only after a request arrives for your daemon’s services. The required and recommended keys for all daemons are:
|Label||Contains a unique string that identifies your daemon to launchd. (required)|
|ProgramArguments||Contains the arguments used to launch your daemon. The first argument is the absolute path to your program executable. (required)|
|inetdCompatibility||Indicates that your daemon requires a separate instance per incoming connection. This causes launchd to behave like inetd, passing each daemon a single socket that is already connected to the incoming client. (required if your daemon was designed to be launched by inetd; otherwise, must not be included)|
|RunAtLoad <boolean>||This optional key is used to control whether your job is launched once at the time the job is loaded. The default is false.|
|StartInterval <integer>||Optional key causes the job to be started every N seconds. If the computer is asleep, the job will be started the next time it wakes up. If multiple intervals occur before the computer wakes, those events will be coalesced into one event.|
|KeepAlive||This key specifies whether your daemon launches on-demand or must always be running. It is recommended that you design your daemon to be launched on-demand and for this reason this key defaults to false.|
The full list of keys for daemon property lists may be found in the online UNIX manual page for launchd.plist which you can access by opening an Application > Utilities > Terminal window and typing man launchd.plist at the prompt.
The property list file is structured the same for both daemons and agents. You indicate whether it describes a daemon or agent by the directory you place it in. Property list files describing daemons are installed in /Library/LaunchDaemons/, and those describing agents are installed in /Library/LaunchAgents/ or in the individual user's ~/Library/LaunchAgents/ subdirectory. The following table lists these directories and describes their correct usage:
|~/Library/LaunchAgents||Per-user agents provided by the user.|
|/Library/LaunchAgents||Per-user agents provided by the administrator.|
|/Library/LaunchDaemons||System-wide daemons provided by the administrator.|
|/System/Library/LaunchAgents||Per-user agents provided by macOS.|
|/System/Library/LaunchDaemons||System-wide daemons provided by macOS.|
The appropriate location for the executable program that you launch as your background process is /usr/local/libexec/.