使用 launchd/launchctl 管理 MacOS 服务

401 阅读3分钟

launchd

launchd is an init and operating system service management daemon created by Apple Inc. as part of macOS to replace its BSD-style init and SystemStarter. There have been efforts to port launchd to FreeBSD and derived systems.

维基百科 所说,launchd 是 MacOS 上所使用的一套服务管理框架。它作为系统启动的第一个进程,系统的其它进程均由它直接或间接创建。

➜  hunterx.xyz git:(master) ✗ ps -ef | grep launchd | grep -v grep
    0     1     0   0 25 623  ??       272:23.76 /sbin/launchd
  213   546     1   0 25 623  ??         4:06.61 /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/Resources/usbmuxd -launchd
    0   567     1   0 25 623  ??        26:32.81 /usr/libexec/corebrightnessd --launchd
    0   582     1   0 25 623  ??         0:13.89 /System/Library/CoreServices/backupd.bundle/Contents/Resources/backupd-helper -launchd
  501  1345     1   0 25 623  ??         0:14.19 /System/Library/PrivateFrameworks/AMPDevices.framework/Versions/A/Support/AMPDeviceDiscoveryAgent --launchd
  501  1653     1   0 25 623  ??         3:26.36 /System/Library/CoreServices/Siri.app/Contents/MacOS/Siri launchd
  501  1658     1   0 25 623  ??         0:24.43 /System/Library/CoreServices/AirPlayUIAgent.app/Contents/MacOS/AirPlayUIAgent --launchd
  501 48141     1   0  9:05上午 ??         0:12.19 /System/Library/PrivateFrameworks/AMPDevices.framework/Versions/A/Support/AMPDevicesAgent --launchd
    0 60348     1   0 18 823  ??         0:00.08 /usr/libexec/xpcroleaccountd -launchd
    0 61549     1   0 18 823  ??         0:02.47 /usr/libexec/biometrickitd --launchd
  501 72715     1   0 19 823  ??         0:04.52 /System/Library/PrivateFrameworks/AMPLibrary.framework/Versions/A/Support/AMPLibraryAgent --launchd
  501 72843     1   0 19 823  ??         0:00.15 /System/Library/PrivateFrameworks/AMPLibrary.framework/Versions/A/Support/AMPArtworkAgent --launchd

在 Linux 系统下,有一个与之对应的进程为 systemd,它的对应管理工具为 systemctl,launchd 的管理工具就是下文所要介绍的 launchctl。

plist 文件

launchd 对一个服务的管理行为需要记录在以 .plist 为后缀的 xml 文件中,通常我们将这类文件称为 plist 文件。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.exampled</string>
  <key>ProgramArguments</key>
  <array>
    <string>exampled</string>
  </array>
  <key>KeepAlive</key>
  <true/>
</dict>
</plist>

不同类型的 plist 文件存放的目录和运行用户有所不同:

类型路径说明
User Agents~/Library/LaunchAgents为当前登录用户启动
Global Agents/Library/LaunchAgents为当前登录用户启动
Global Daemons/Library/LaunchDaemonsroot 或者通过 UserName 配置指定的用户
System Agents/System/Library/LaunchAgents当前登录用户
System Daemons/System/Library/LaunchDaemonsroot 或者通过 UserName 配置指定的用户

launchctl 使用

使用 launchctl 可以非常方便地对查询/添加/删除服务,以下是我经常使用到的一些命令:

# 列出当前加载的服务
launchctl list

# 卸载某一个服务
launchctl unload xyz.hunterx.plist

# 加载某一个服务
launchctl load xyz.hunterx.plist

# 无视 Disabled 配置值,加载并启动某一个服务
launchctl load -w xyz.hunterx.plist

注意事项

  1. 如果一个服务之前已经被加载,使用 launchctl load 命令时会报错,可以尝试先对服务进行卸载:

    launchctl list | grep xyz.hunterx.plist && launchctl unload xyz.hunterx.plist
    
  2. 如果启动的服务需要一些环境变量(如用户登录后自动 source 引入的变量),需要在配置中使用 EnvironmentVariables 定义:

    <?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.exampled</string>
      <key>ProgramArguments</key>
      <array>
        <string>exampled</string>
      </array>
      <key>KeepAlive</key>
      <true/>
      <key>EnvironmentVariables</key>
      <dict>
        <key>PYTHON_PATH</key>
        <key>/usr/bin/python</key>
      </dict>
    </dict>
    </plist>
    

参考资料

  1. 使用 launchctl 管理 MacOS 服务
  2. macOS服务管理 – launchd、launchctl、brew services详解
  3. launchd wikipedia
  4. launchd.plist