简体   繁体   中英

Enable, disable and start services programmatically in macOS

I am writing a program that comes with a service. What I did so far is to create a helper tool that can run elevated tasks for my process and can communicate via XPC.

My program comes bundled with a service and I want to use the helper tool to install and start/stop this service so my program can have a checkbox "start service with system" in the settings.

I can successfully copy the plist for the service, but I cannot find any way to enable, disable, start or stop the service programmatically. I think the solution to call system("launchctl load /path/to/service.plist");pretty ugly. Is there any mechanism in objective C to accomplish this task and get a success or failed result?

Apple has a deprecated C API for starting, stopping, and enabling launchd services in launch.h . The source code for the API is on their opensource site: https://opensource.apple.com/source/launchd/launchd-442.26.2/liblaunch/

Here's some sample code that asks launchd to start the LittleSnitchUIAgent service:

#include <launch.h>

int main(int argc, const char * argv[]) {
    const char *job = "at.obdev.LittleSnitchUIAgent";
    launch_data_t resp, msg;
    msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
    launch_data_dict_insert(
        msg, launch_data_new_string(job), LAUNCH_KEY_STARTJOB);
    resp = launch_msg(msg);
    launch_data_free(msg);
    return 0;
}

The LittleSnitchUIAgent isn't signification -- I chose it at random from my local list of services. I left error checking out of the sample to keep it straight forward.

If you haven't already I would recommend giving the launchd man pages and the Daemons and Services Programming Guide a very close study. Launchd can start your processes in response to almost anything: a timer, a socket connection, a device being added to the system, among many others. It's rare that you actually need to manage your own services. I haven't been able to confirm this but I suspect that's why they've deprecated the API.

Looks like there is a ServiceManagement API/Framework used to load LaunchAgents. Looks SMJobBless is the only method available

From ObjC you could always use the NSTask to manipulate daemons and agents using the launchctl command-line.

Examples:

- (BOOL)isDaemonLoaded:(NSString *)daemonLabel {
    NSTask *task = [NSTask new];
    [task setLaunchPath:@"/bin/launchctl"];
    [task setArguments:@[@"list", daemonLabel]];
    [task launch];
    [task waitUntilExit];
    // return code 0 is for loaded daemon, and much info is in stdout, and 113 or other nonzero value when daemon is not loaded
    return ([task terminationStatus] == 0);
}

or, starting/stopping a launchd global daemon:

typedef NS_ENUM(BOOL, DaemonState)
{
    DaemonStateOff = NO,
    DaemonStateOn = YES
};
- (BOOL)switchGlobalDaemon:(NSString *)daemonLabel 
                     state:(DaemonState)newState {
    NSString *command = (newState == OITStateOn) ? @"load" : @"unload";
    NSString *daemonPath = [[@"/Library/LaunchDaemons" stringByAppendingPathComponent: daemonLabel] stringByAppendingPathExtension:@"plist"];
    if (NO == [[NSFileManager defaultManager] fileExistsAtPath:daemonPath])
        return NO;

    NSTask *task = [NSTask new];
    [task setLaunchPath:@"/bin/launchctl"];
    [task setArguments:@[command, daemonPath]];
    [task launch];
    [task waitUntilExit];
    return ([task terminationStatus] == 0);
}

Of course any launchctl command can be wrapped like this. It looks silly to do this, but since Apple removed programmatic APIs and left us with launchctl...

Anyways, there are quite a few ways to manage your daemons and agents the "straight" way - by setting the rules in the.plist, and letting launchd apply the rules.

Only sometimes there are business logic consideration outside the MacOS domain (say - a notification from a remote server, via push-notifications, telling you to turn off some service, because the customer stopped paying...) or to change configuration of a running service - but that won't take effect until you relaunched it. So it may be still useful to know this technique.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM