英文:
getppid() returns 1 when double-clicking macOS bundle app
问题
I have a macOS GUI app, which is also functionally capable of running as a background service i.e., Agent or a Daemon.
The main entry point is main.swift file, where I set some values and invoke some OS calls to understand if my app was launched a service (Agent or Daemon) or a GUI app.
import Foundation
// Set some variables
// Call an ObjC++ func which does the following:
// {
// if(getppid() == 1) {
// // Prepare app to function as a daemon/agent
// // Return to swift
// } else {
// // Prepare app to function as a GUI app
// // Return to swift
// }
// Back in swift layer, start initializing the NSApplication object and
// set the NSApplicationDelegate.
Lets not get into why I'm not using @main attribute, which removes this boilerplate code... Now, when I build this app using Xcode, launch it from the builds folder, I see that getppid() - the Linux OS call to know the parent process ID, returns 1, which means, app is a daemon or an agent (as all services are children of the init process, which has pid of 1).
I'm not creating any new threads nor invoking fork(), both of which can cause the main thread to be returned to OS... which leads to init process adopting the app.
Why does getppid() return 1 when the app is launched by double clicking from Finder? Finder is the parent process in this case, right?
Update1:
As pointed out in Arthur's answer and Barmar's comment (in the question) - When I launch Safari and then checked its PPID using the 'top' command in terminal.
Output:
PID COMMAND %CPU TIME #TH #WQ #PORTS MEM PURG CMPRS PGRP PPID
5134 Safari 0.0 00:02.72 7 4 443 55M 9792K 0B 95134 1
94818 Xcode 0.0 00:17.81 10 3 569 469M 864K 0B 94818 1
As shown above, the PPID of Safari and Xcode is 1.
英文:
I have a macOS GUI app, which is also functionally capable of running as a background service i.e., Agent or a Daemon.
The main entry point is main.swift file, where I set some values and invoke some OS calls to understand if my app was launched a service (Agent or Daemon) or a GUI app.
// main.swift
import Foundation
// Set some variables
// Call an ObjC++ func which does the following:
// {
// if(getppid() == 1) {
// // Prepare app to function as a daemon/agent
// // Return to swift
// } else {
// // Prepare app to function as a GUI app
// // Return to swift
// }
// Back in swift layer, start initializing the NSApplication object and
// set the NSApplicationDelegate.
Lets not get into why I'm not using @main attribute, which removes this boilerplate code...
Now, when I build this app using Xcode, launch it from the builds folder, I see that getppid() - the Linux OS call to know the parent process ID, returns 1, which means, app is a daemon or an agent (as all services are children of the init process, which has pid of 1).
I'm not creating any new threads nor invoking fork(), both of which can cause the main thread to be returned to OS... which leads to init process adopting the app.
Why does getppid() return 1 when app is launched by double clicking from Finder? Finder is the parent process in this case, right?
Update1:
As pointed out in Arthur's answer and Barmar's comment (in the question) - When I launch Safari and then checked its PPID using the 'top' command in terminal.
Output:
PID COMMAND %CPU TIME #TH #WQ #PORTS MEM PURG CMPRS PGRP PPID
5134 Safari 0.0 00:02.72 7 4 443 55M 9792K 0B 95134 1
94818 Xcode 0.0 00:17.81 10 3 569 469M 864K 0B 94818 1
As shown above, the PPID of Safari and Xcode is 1.
答案1
得分: 1
抱歉,我无法提供翻译,因为你的请求是要求不提供翻译。如果你有其他需要,请随时告诉我。
英文:
There is no valid process-tree in macOS world, unfortunately.
All unix stuff like getppid will return something valid only for the processes launched in a unix way, let's say running some console binaries from Terminal could show you behaviour you expect here.
GUI processes are launched on macOS in a complex way including 1+ IPC from the real source process who wants something to launch to the launchd.
Regarding your initial goal, I would say the most straightforward will be just to add some commandline argument or env variable into its launch plist, and check it then: if it is present - the app is launched as agent/daemon, if it is not - use GUI logic.
I've answered a question alike (a bit more complex) before here, if you want to read more on topic
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论