Skip to content

launchdlaunchctl

launchdmacos系统下的服务管理框架,用于启动,停止,管理守护进程和服务,是第一个进程,PID为1,创建了所有其他进程

launchctllaunchd的管理工具,二者之间的关系类似于linux系统的systemdsystemctl

基本逻辑

  1. launchd启动后,扫描/System/Library/LaunchDaemons/Library/LaunchDaemons中的plist文件并加载,以root或者指定用户权限运行,在开机未输入密码的时候就开始运行,如果要配置开机自启动服务,推荐把plist文件放到/Library/LaunchDaemons

  2. 输入密码登入系统后,扫描/System/Library/LaunchAgents/Library/LaunchAgentsplist文件所有用户可见)、~/Library/LaunchAgentsplist当前用户可见)这三个目录中的plist文件并加载,以当前用户权限运行,在开机并且输入账号密码之后开始运行

  3. 每一个plist文件,都叫一个Job(即一个任务),只有plist里设置了RunAtLoadtruekeepAlivetrue时,才会在加载这些plist文件的同时启动plist所描述的服务

下面开始编写plist文件并加载运行,重启验证

plist文件

通过.plist后缀结尾的xml文件来定义一个服务

创建一个配置文件/Library/LaunchDaemons/com.example.plist

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.example</string>
    <key>KeepAlive</key>
    <true/>
    <key>ProcessType</key>
    <string>Background</string>
    <key>ProgramArguments</key>
    <array>
      <string>sh</string>
      <string>-c</string>
      <string>while true; do pwd && date && sleep 1; done</string>
    </array>
    <key>UserName</key>
    <string>root</string>
    <key>GroupName</key>
    <string>wheel</string>
    <key>StandardErrorPath</key>
	<string>/var/log/com.example.log</string>
	<key>StandardOutPath</key>
	<string>/var/log/com.example.log</string>
    <key>WorkingDirectory</key>
    <string>/Applications/example</string>
  </dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.example</string>
    <key>KeepAlive</key>
    <true/>
    <key>ProcessType</key>
    <string>Background</string>
    <key>ProgramArguments</key>
    <array>
      <string>sh</string>
      <string>-c</string>
      <string>while true; do pwd && date && sleep 1; done</string>
    </array>
    <key>UserName</key>
    <string>root</string>
    <key>GroupName</key>
    <string>wheel</string>
    <key>StandardErrorPath</key>
	<string>/var/log/com.example.log</string>
	<key>StandardOutPath</key>
	<string>/var/log/com.example.log</string>
    <key>WorkingDirectory</key>
    <string>/Applications/example</string>
  </dict>
</plist>

标签说明

  • Label服务的名称,值是全局唯一的,Label值推荐与.plist的文件名称部分保持一致

  • Keepalive: 决定程序是否需要一直运行,如果是false 则需要时才启动,默认false

  • ProcessType: 程序类型,系统会依据不同的程序类型应用不同的资源限制策略,主要是限制CPU和磁盘I/O带宽,可选项如下

    • Backgroud: 通常是执行用户没有直接请求的进程,应用的资源限制旨在防止破坏用户体验,资源限制最严格
    • Standard: 默认值,标准限制
    • Adaptive: 基于XPC连接上的活动限制资源
    • Interactive: 交互式级别的限制,相当于app程序的资源限制,可以拥有最高的性能,所以基本是无限制资源
  • ProgramArguments:程序的参数信息,包含程序调用的命令,命令的参数等信息

  • UserName: 程序运行用户权限

  • GroupName: 程序运行用户组

  • StandardErrorPath: 标准错误输出日志的路径,如果不配置则无输出

  • StandardOutPath: 标准输出日志的路径,如果不配置则无输出

  • WorkingDirectory: 指定程序的工作目录位置,如果是放在/Library/LaunchDaemons/的文件,默认工作目录是/配置完成该参数之后需要保证该路径存在,否则服务不能正常启动

服务加载运行

加载服务配置

shell
$ launchctl load /Library/LaunchDaemons/com.example.plist
$ launchctl load /Library/LaunchDaemons/com.example.plist

卸载服务配置,如果配置修改之后,需要先卸载配置,然后再次执行加载

shell
$ launchctl unload /Library/LaunchDaemons/com.example.plist
$ launchctl unload /Library/LaunchDaemons/com.example.plist

启动停止服务,由于服务配置Keepalive=true服务执行load之后就直接开始运行了,启动停止命令不生效

shell
$ launchctl start com.example.plist
$ launchctl stop com.example.plist
$ launchctl start com.example.plist
$ launchctl stop com.example.plist

查看服务运行状态,共三列数据

shell
$ launchctl list|grep com.example
9919	0	com.example
$ launchctl list|grep com.example
9919	0	com.example
  • 第一列表示进程PID,有值表示进程正在运行中

  • 第二列表示执行之后的返回码,如果是0表示执行无报错

  • 第三列表示服务的Label

依据配置StandardErrorPath/StandardOutPath检查日志输出

shell
$ tail -f /var/log/com.example.log 
/Applications/example
Mon Jun 19 16:31:01 CST 2023
/Applications/example
Mon Jun 19 16:31:02 CST 2023
/Applications/example
Mon Jun 19 16:31:03 CST 2023
/Applications/example
Mon Jun 19 16:31:04 CST 2023
/Applications/example
Mon Jun 19 16:31:05 CST 2023
$ tail -f /var/log/com.example.log 
/Applications/example
Mon Jun 19 16:31:01 CST 2023
/Applications/example
Mon Jun 19 16:31:02 CST 2023
/Applications/example
Mon Jun 19 16:31:03 CST 2023
/Applications/example
Mon Jun 19 16:31:04 CST 2023
/Applications/example
Mon Jun 19 16:31:05 CST 2023

可以重启设备之后继续校验服务是否开机自启动

其他注意事项

如果服务的ProgramArguments参数中,如果执行的命令如果会修改到当前.plist文件,在执行加载plist文件,比如launchctl load com.example.plist,程序无报错,也无输出,使用launchctl list命令也找不到对应的服务注册信息,这个是正常的,macos可能有某种机制控制服务不能修改自己的服务配置文件

参考阅读

macOS服务管理 – launchd、launchctl、brew services详解

launchd.plist man page

Last updated:

Released under the MIT License.