A launchd job without plist file, how does that work and how to find what job triggers it

launchd

I am having a hard time to figure out how those unwanted program autostarted in the system. I am running MacOS Big Sur.

Take an example, Please have a look at the following job:

$ launchctl list | grep -i thunder
405 0   com.xunlei.Thunder.ThunderHelper
$ launchctl print gui/$(id -u)/com.xunlei.Thunder.ThunderHelper
com.xunlei.Thunder.ThunderHelper = {
    active count = 4
    copy count = 0
    one shot = 0
    path = (submitted by otherbsd.330)
    state = running

    program identifier = com.xunlei.Thunder.ThunderHelper
    parent bundle identifier = com.xunlei.Thunder
    parent bundle version = 4368
    inherited environment = {
        SSH_AUTH_SOCK => /private/tmp/com.apple.launchd.ZGX7Lm6JIp/Listeners
    }

    default environment = {
        PATH => /usr/bin:/bin:/usr/sbin:/sbin
    }

    environment = {
        XPC_SERVICE_NAME => com.xunlei.Thunder.ThunderHelper
    }

    domain = com.apple.xpc.launchd.user.domain.501.100006.Aqua
    asid = 100006
    minimum runtime = 10
    exit timeout = 5
    runs = 1
    successive crashes = 0
    pid = 405
    immediate reason = semaphore
    forks = 0
    execs = 1
    initialized = 1
    trampolined = 1
    started suspended = 0
    proxy started suspended = 0
    last exit code = (never exited)

    semaphores = {
        successful exit => 0
    }

    event triggers = {
    }

    endpoints = {
        "com.xunlei.Thunder.ThunderHelper" = {
            port = 0x9a333
            active = 0
            managed = 1
            reset = 0
            hide = 0
        }
    }

    dynamic endpoints = {
        "com.xunlei.Thunder.MessageHelper" = {
            port = 0xac607
            active = 1
            managed = 0
            reset = 0
            hide = 0
        }
    }

    pid-local endpoints = {
        "com.apple.tsm.portname" = {
            port = 0xbecaf
            active = 1
            managed = 0
            reset = 0
            hide = 0
        }
        "com.apple.axserver" = {
            port = 0xbe833
            active = 1
            managed = 0
            reset = 0
            hide = 0
        }
    }

    instance-specific endpoints = {
    }

    event channels = {
    }

    sockets = {
    }

    instances = {
    }

    spawn type = interactive (4)
    jetsam priority = 3
    jetsam memory limit (active) = (unlimited)
    jetsam memory limit (inactive) = (unlimited)
    jetsamproperties category = daemon
    submitted job. ignore execute allowed
    jetsam thread limit = 32
    cpumon = default
    job state = running

    properties = {
        partial import = 0
        xpc bundle = 0
        keepalive = 0
        runatload = 0
        low priority i/o = 0
        low priority background i/o = 0
        dataless file mode = 0
        legacy timer behavior = 0
        exception handler = 0
        supports transactions = 1
        supports pressured exit = 0
        supports idle hysteresis = 0
        enter kdp before kill = 0
        wait for debugger = 0
        app = 0
        system app = 0
        creates session = 0
        inetd-compatible = 0
        inetd listener = 0
        abandon process group = 0
        event monitor = 0
        penalty box = 0
        role account = 0
        launch only once = 0
        system support = 0
        inferred program = 0
        joins gui session = 0
        joins host session = 0
        parameterized sandbox = 0
        resolve program = 1
        abandon coalition = 0
        high bits aslr = 0
        reslide shared cache = 0
        disable resliding = 0
        extension = 0
        nano allocator = 0
        no initgroups = 0
        start on fs mount = 0
        needs implicit endpoint = 0
        is copy = 0
        disallow all lookups = 0
        system service = 0
        protected by submitter = 0
        multiple instances = 0
    }
}

I am wondering how this job started automatically? How does it really work?

What does submitted by otherbsd.330 path mean here?

I don't find a plist file anywhere which is responsible for this job.

Thanks a lot.


Btw, I am not sure the following words related to this question or not. You can ignore the following words. I just want to provide more information which may help on this issue.

I asked another question regarding how to delete hidden login iterms from $HOME/Library/Application Support/com.apple.backgroundtaskmanagementagent/backgrounditems.btm. So far, there is no answer yet. Inside backgrounditems.btm, it has this ThunderHelper process too. Since I don't find a proper way to delete the login iterm. It's hidden and not shown in system preferences. I delete the file compeletely with command rm backgrounditems.btm, but magically, after I shutdown and restart the system, this login iterm will automatically be created again inside a new backgrounditems.btm file.

I am thinking to change this file's owner and group permission. Make root as the owner and other user only readable permission. I haven't tried this approach. Hopefully, it will work.

Best Answer

launchd jobs can be submitted directly (through launchctl, and likely through cocoa code) without using a plist file. Since I see this line:

parent bundle identifier = com.xunlei.Thunder

that suggests the application with that bundle identifier (probably 'Xunlei Thunder', a peer-to-peer networking thing) is setting up a helper app (ThunderHelper) to run independently in the background.