←→ Underneath: Background Apps · 所有 Mac 指南

為什麼 Mac 重新開機後 App 又回來了

你結束了它,甚至在活動監視器中強制結束了它。兩秒後,或是下次重新開機後,它又在執行了。有東西刻意在啟動它。在 Mac 上,這個東西幾乎總是 launchd。

簡短回答:這個 App 有一個 launchd 工作。RunAtLoad 會在每次登入時啟動它,KeepAlive 則會在它停止時再次啟動它。結束程序並不會改變工作。若要永久停止,請停用工作,而不是程序。

launchd 是什麼

launchd 是 macOS 啟動的第一個程序(程序 ID 1),幾乎其他所有東西都是由它啟動的。它會讀取小小的 .plist 檔案,這些檔案稱為工作,說明要執行什麼以及何時執行。每個工作都有一個標籤,也就是像 com.google.keystone.agent 這樣的唯一名稱。

App 會把工作安裝在 ~/Library/LaunchAgents、/Library/LaunchAgents 或 /Library/LaunchDaemons 中,或從自己的 App 套件內註冊。

讓 App 回來的鍵

以下是一個典型的啟動代理程式:

<key>Label</key>
<string>com.example.helper</string>
<key>ProgramArguments</key>
<array>
  <string>/Applications/Example.app/Contents/MacOS/Helper</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
鍵效果你會看到
RunAtLoad工作一載入就啟動,也就是每次登入時(代理程式)或開機時(常駐程式)每次重新開機後它都在
KeepAlive = true程序每次結束時都重新啟動它強制結束沒有用;幾秒內它就回來了
KeepAlive 附條件只在某些情況下重新啟動,例如當機後(SuccessfulExit = false)或網路連線期間它有時會回來,但不是每次
StartInterval每 N 秒執行一次它出現、短暫執行、消失,然後重複
StartCalendarInterval像 cron 一樣在設定的時間執行它每天在同一時間出現
WatchPaths在檔案或檔案夾變更時執行它在你做了不相關的事之後出現

對於不斷結束的工作,launchd 會在每次重新啟動之間等待約 10 秒,因此 KeepAlive 工作看起來也可能像是在「閃爍」。

App 回來的其他原因

找出是哪一個

  1. 找出工作標籤。使用 App 或開發者名稱的一部分執行 launchctl list | grep -i example。第三欄就是標籤。
  2. 讀取工作內容:
    launchctl print gui/$(id -u)/com.example.helper
    查看 path(plist 檔案)、state、runs(啟動了幾次)和 last exit code。啟動次數很高通常代表 KeepAlive。
  3. 打開 plist,檢查 RunAtLoad、KeepAlive 和間隔相關的鍵。
  4. 如果沒有工作,請檢查「登入時打開」和 App 本身的設定。

停止與停用的差別

你的操作會回來嗎?
結束或強制結束程序會:若有 KeepAlive 會立刻回來,若有 RunAtLoad 則在下次登入時
launchctl bootout gui/$(id -u)/label現在不會。若有 RunAtLoad,下次登入時會
launchctl disable gui/$(id -u)/label + bootout不會,直到你執行 launchctl enable
將 plist 移出 LaunchAgents + bootout不會,直到你把它移回去
在「允許在背景執行」中關閉不會,直到你重新打開

逐步指令請見如何安全地停用啟動代理程式。

常見問題

為什麼我在活動監視器中結束程序後,它馬上又重新啟動?

因為它的 launchd 工作設定了 KeepAlive。launchd 會監看該程序,在它結束時再次啟動它。請用 launchctl bootout 停止該工作,而不是結束程序。

RunAtLoad 是什麼意思?

RunAtLoad 是 launchd plist 中的一個鍵。當它為 true 時,launchd 一載入 plist 就會啟動工作;對啟動代理程式來說,就是每次登入時都會啟動。

KeepAlive 是什麼意思?

KeepAlive 會要求 launchd 讓工作持續執行。如果程序結束或被終止,launchd 會再次啟動它。它也可以是一組條件,例如只在當機後重新啟動。

停止和停用啟動代理程式有什麼差別?

停止(launchctl bootout)會卸載工作,直到下次登入或重新開機。停用(launchctl disable,或將 plist 移出 LaunchAgents)則會讓它在重新開機後不再被載入。