6

The users of my app can choose if they want (or not) launch my app at their session startup.

To do this, I use LSSharedFileListRef as described here : How do you make your App open at login?

What I want now is to know if my app has been launched automatically at session startup or via a click on the icon in the dock. Indeed, I have to do different actions in these two cases.

I have got the feeling that it is not possible to use the parameters of the notification in the following delegate method to do this:

- (void)applicationDidFinishLaunching:(NSNotification *)notification

I have seen the following posts but they do not help:

How can I know how my app was launched on Mac OS? => NO ANSWER except some links to other posts which do not help more...

Know if the user launched an app => I don't see how to set/get the "Y" parameter defined in this post

Mac OS X: open application at login, without showing the main window => deals with the fact to hide or not the main window at startup ; what I want is more general: how to know how the app has been launched?

Anybody can help me ?

Thanks !

Community
  • 1
  • 1
toto_tata
  • 14,526
  • 27
  • 108
  • 198
  • By checking the time of launching of OS and the specified app. – Anoop Vaidya Jan 04 '13 at 17:41
  • 1
    Thanks, it is one way (not completely reliable but why not...) but I can't find out how to determine when the OS has been launched. Any idea ? – toto_tata Jan 04 '13 at 17:55
  • have you managed to use the ppid (parent process id) to determine this? I am afraid ppid may be 1 also when user double-clicks the app... how did you solve the problem? – Motti Shneor Nov 17 '20 at 13:50

4 Answers4

2

If application is set to run at startup, it will run (why not?). So you can save the application start time somewhere. And on the later run (for instance, user quit your application and run again) check if there is this parameter, and if it is later than system boot time, than application this time is not run automatically.

You can check the system boot time via [NSProcessInfo systemUptime]

Nickolay Olshevsky
  • 13,706
  • 1
  • 34
  • 48
2

I'd check Parent Process ID. If it equals 1 it means it was launched by launchd at start up time.

struct kinfo_proc info;
size_t length = sizeof(struct kinfo_proc);
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
if (sysctl(mib, 4, &info, &length, NULL, 0) < 0)
    return OPProcessValueUnknown;
if (length == 0)
    return OPProcessValueUnknown;

 //info.kp_eproc.e_ppid is what you need 
bioffe
  • 6,283
  • 3
  • 50
  • 65
  • Thanks for your answer. I am going to test this. Nevertheless, I have some questions: is it normal that you return OPProcessValueUnknown in both cases ? What do you mean by "info.kp_eproc.e_ppid is what you need " ? Thanks !! – toto_tata Jan 05 '13 at 10:36
  • @Regis_AG OPProcessValueUnknown is just some constant that tells you there was a problem with sysctl. This code is portable, if you don't care you can just use getppid(2). if info.kp_eproc.e_ppid == 1 it means this process was launched at startup time. – bioffe Jan 05 '13 at 19:33
  • Thanks bioffe. Neverthless, I am really not used to use this kind of system function and I still don't know how to proceed. Are you sure that it is getppid(2) and not GETPID(2) ? What is "info" ? Is it returned by getppid(2) ? The best would be that you write the entire code, something like that I imagine: SOMETYPE info = getppid(2); if (info.kp_eproc.e_ppid == 1){//Means this process was launched at startup time}. Thanks !!! – toto_tata Jan 07 '13 at 10:47
  • Yes, I am sure. We, programmers, should be very careful with references we provide. Everything I typed above can be copy-pasted and will work. info is a veritable defined in the very first line. – bioffe Jan 07 '13 at 19:51
  • 4
    @bioffe I'm getting `1` for `info.kp_eproc.e_ppid` for both "open-at-login" launches *and* launches from the Applications folder. Building and Running via Xcode does indeed give a different id though. How do we distinguish between Open At Login and manual launches from Finder? – ck_ Apr 22 '13 at 20:29
  • @cksubs here is what I've done. I launched Safari via Finder.app and opened a console. Typed `ps -ef` to find out its PPID. In my case it was 118 which is 'launchd'. Interestingly PPID for process 118 was process ID 1. All tools that started at user session startup have PPID 1. All apps started via finder have PPID 118 which is different instance of the same process. – bioffe Apr 23 '13 at 15:32
  • @bioffe ok, I'm seeing how the PPID of the app (launched via Finder) is always the PID of `launchd`. However, I'm never seeing an "open at login" app get a PPID of 1. It's also getting the PPID of `launchd`. Is this working incorrectly based on the way that the app is opened at login? – ck_ Apr 24 '13 at 02:56
  • @bioffe I tested this by adding `Chess.app` to the open-at-login list at SystemPrefs>Users>LoginItems. When (OS X 10.8) that user logs out and then back in, I get `CHESS: UID = 502, PID = 27551, PPID = 15129`. Chess's PPID corresponds to `launchd, PID = 15129` – ck_ Apr 24 '13 at 03:19
  • 2
    @cksubs I see now. You are using SystemPrefs>Users>LoginItems which is no different from launching via Finder. Don't know much about LaunchServices. We used to launch things at session startup via launchd /Library/LaunchAgents route. Not sure if it's 10.8 friendly anymore. – bioffe Apr 24 '13 at 03:58
1

If you can't get @bioffe's answer to work, here it is again with a little more:

From: http://www.objectpark.net/parentpid.html

#include <sys/sysctl.h>

#define OPProcessValueUnknown UINT_MAX

//Returns the parent process id for the given process id (pid).
int OPParentIDForProcessID(int pid)
{
    struct kinfo_proc info;
    size_t length = sizeof(struct kinfo_proc);
    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
    if (sysctl(mib, 4, &info, &length, NULL, 0) < 0)
        return OPProcessValueUnknown;
    if (length == 0)
        return OPProcessValueUnknown;
    return info.kp_eproc.e_ppid;
}
ck_
  • 3,719
  • 10
  • 49
  • 76
  • what's wrong with simple call to getppid() from usr/include/unistd.h ??? Also - I'm afraid ppid is also 1 when user double-clicks an app. – Motti Shneor Nov 17 '20 at 13:51
-1

Open a Terminal window, type last | grep '^reboot' | awk 'END { print $3" "$4" "$5" "$6 }' to get the reboot time and match the time of the specific application launch, as @AnoopVaidya pointed out.

hd1
  • 33,938
  • 5
  • 80
  • 91