←→ Underneath: Background Apps · すべてのMacガイド
Macを再起動するとアプリが戻ってくる理由
終了した。アクティビティモニタで強制終了までした。それなのに2秒後、または次の再起動後に、また動いている。何かが意図的に起動しているのです。Macの場合、その「何か」はほぼ必ずlaunchdです。
結論:そのアプリにはlaunchdジョブがあります。RunAtLoadはログインのたびにジョブを起動し、KeepAliveは止まるたびに再び起動します。プロセスを終了しても、ジョブは変わりません。完全に止めるには、プロセスではなくジョブを無効にします。
launchdとは
launchdはmacOSが最初に起動するプロセス(プロセスID 1)で、ほかのほぼすべてを起動します。launchdは小さな.plistファイルを読み込みます。これはジョブと呼ばれ、何をいつ実行するかを記述しています。各ジョブにはラベルがあり、com.google.keystone.agentのような一意の名前です。
アプリはジョブを~/Library/LaunchAgents、/Library/LaunchAgents、/Library/LaunchDaemonsにインストールするか、自分のアプリバンドル内から登録します。
アプリを呼び戻すキー
典型的なLaunchAgentの例です:
<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のジョブが「点滅」しているように見えることもあります。
アプリが戻ってくるその他の理由
- ログイン時に開く。アプリがシステム設定 › 一般 › ログイン項目と機能拡張に登録されています。macOSはログインのたびにそのアプリを開きます。
- 再ログイン時にウインドウを再度開く。「再起動」と「システム終了」のダイアログにあるこのチェックボックスは、開いていたすべてのアプリを復元します。
- アプリが自分を再登録する。アプリ自体の「ログイン時に起動」の設定が、実行するたびにアプリを登録し直します。
- ヘルパーがメインのアプリを開く。小さなバックグラウンドヘルパーが先に起動し、たとえば同期の状態を表示するためにアプリ本体を開きます。
- Homebrewサービス。
brew services startはRunAtLoad付きのLaunchAgentを書き込みます。停止するにはbrew services stop <name>を使います。
どれが原因か調べる
- ジョブのラベルを調べます。アプリ名や開発元名の一部を使って
launchctl list | grep -i exampleを実行します。3列目がラベルです。 - ジョブの内容を読みます:
launchctl print gui/$(id -u)/com.example.helperpath(plistファイル)、state、runs(起動した回数)、last exit codeを確認します。起動回数が多い場合、たいていはKeepAliveが原因です。 - plistを開いて、
RunAtLoad、KeepAlive、間隔のキーを確認します。 - ジョブがない場合は、「ログイン時に開く」とアプリ自体の設定を確認します。
停止と無効化の違い
| 行う操作 | 戻ってくる? |
|---|---|
| プロセスを終了または強制終了 | はい:KeepAliveならすぐに、RunAtLoadなら次回ログイン時に |
launchctl bootout gui/$(id -u)/label | いまは戻らない。RunAtLoadなら次回ログイン時に戻る |
launchctl disable gui/$(id -u)/label + bootout | いいえ(launchctl enableを実行するまで) |
| plistをLaunchAgentsの外に移動 + bootout | いいえ(元に戻すまで) |
| 「バックグラウンドでの実行を許可」でオフにする | いいえ(オンに戻すまで) |
コマンドの手順はLaunchAgentを安全に無効にする方法にあります。
よくある質問
アクティビティモニタで終了したプロセスがすぐに再起動するのはなぜですか?
そのlaunchdジョブにKeepAliveが設定されているからです。launchdはプロセスを監視し、終了すると再び起動します。プロセスを終了するのではなく、launchctl bootoutでジョブを停止してください。
RunAtLoadとはどういう意味ですか?
RunAtLoadはlaunchdのplistのキーです。trueの場合、launchdはplistを読み込んだ時点でジョブを起動します。LaunchAgentの場合、これはログインするたびに起動するという意味です。
KeepAliveとはどういう意味ですか?
KeepAliveは、ジョブを動かし続けるようlaunchdに指示します。プロセスが終了したり強制終了されたりすると、launchdが再び起動します。クラッシュ後にだけ再起動するなど、条件の組み合わせにすることもできます。
LaunchAgentの停止と無効化の違いは何ですか?
停止(launchctl bootout)は、次回のログインまたは再起動までジョブの読み込みを解除します。無効化(launchctl disable、またはplistをLaunchAgentsの外に移動)は、再起動後にジョブが再び読み込まれないようにします。