I'm a developer using Lazarus Pascal, so converting ObjC and Swift comes with its challenges.
I'm trying to figure how to properly use SMAppService to add my application as a login item for the App Store.
I have learned that the old method (< macOS 13) uses a helper tool, included in the app bundle, which calls the now deprecated SMLoginItemSetEnabled. Now this is already quite a pain to deal with if you're not using XCode, not to mention converting the headers being rather complicated when you're not experienced with doing this.
The "new" method (as of macOS 13) is using SMAppService.
Can anyone explain how to use this? The documentation (for me anyway) is a not very clear about that and neither are examples that can be found all over the Internet.
My main question is:
Can I now use the SMAppService functions to add/remove a login item straight in my application, or is a helper tool still required?
Service Management
RSS for tagThe Service Management framework provides facilities to load and unload launched services and read and modify launched dictionaries from within an application.
Posts under Service Management tag
79 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
I am encountering an issue with my application, BloxOneEndpoint.pkg, which includes two services:
rc_service_infoblox – Runs as the root user.
Controller Application – Runs as a normal user.
Although a thread within rc_service_infoblox is running fine and performing its expected tasks, I notice that the service appears as "Not Responding" in Activity Monitor. Despite normal functionality, this status is concerning, as it may indicate some issue to customer.
I would appreciate any insights into why this might be happening and how to resolve it. Is there a specific API or mechanism I should use to ensure the service remains in a "Running" state in Activity Monitor?
Thank you for your guidance.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Endpoint Security
Service Management
We are building a 'server' application that can either run as a daemon or can run in background without showing any GUI. Basically, the end user can either configure this to run as a daemon so that it can be tied to the user's session or will launch the process which user will start and quit as needed.
I wanted to understand what is the recommended mechanism for such an application from Apple -
Should this application be built as a macOS Bundle ? Apple documentation also says that we should not daemonize the process by calling fork. Hence if we create a unix-style executable, will I not need to fork to make it run in a detached state when I launch the executable via double-click ? [Reference Link]
Is it fine to have an application on macOS which is a bundle but does not show any UI when launched by double click on the app-icon or via 'open'? While we have been able to achieve this by using NSApplicationMain and not showing the UI, was wondering if using CFRunLoop is best for this case as it is a non-gui application.
If we can get the right documentation link or recommendations on how we should build such an application which can run in a non-gui mode and also in a daemonized manner, it will help us.
Should the application be always built as a macos bundle or should it be a unix-style executable to support both the cases - by the same application/product and how should we look at the distribution of such applications.
Hello,
My current app bundle structure is I have a sandboxed GUI and a unsandboxed launch agent that does the core logic of my app. Our pkg post install scripts handles bootstrapping the Launch Agent plists defined in /Library/Launch Agents. I have been tasked with creating a restart/exit button on the UI which terminates the Launch Agent (essentially bootout command in launchctl) and terminates the UI as well. I have attempted to follow the SMAppServcice.agent(plistName) and changed Program key to BundleProgram and changed the value to the relative path as in example provided in Apple Docs (old launch agent plist attached, and new bundle build phase style attached. I have been unable to register or unregister the launch agent via the UI, and in the initial case when trying to call unregister the launch agent got removed and i got "Operation not permitted" with error kSMErrorInvalidSignature seems like some code signature issue im not aware of. I wasnt even able to bootstrap the launch agent back until I found a script which reset such launchctl settings. My question is: is the sandboxed UI not able to do this (and why is this not documented in the dev docs I have no idea), and if so then how would I go about terminating both services and also being able to restart them? This seems like a common use case the UI should be able to handle as far as ownership of running/booting out its resources.
).
Can I launch all the launchAgents associated with a user before they log in? If so, is there an event or mechanism I can use or simulate to achieve this?
Is it possible to delay the login mechanism, till all the launchAgents are loaded.
Looking for guidance on how to approach this.
My question is: Do I need two App IDs? One for my launch daemon in order to sign it properly, allowing it to use the Endpoint Security framework. One for the container app.
My understanding is that my existing launch daemon can perform the endpoint security requirements I need. So far, I have had just one App ID for my container app that lives in /Applications.
I have applied for the endpoint security restricted entitlement and have this for development now.
Do endpoint security items have go in Library/SystemExtension? Can my launch daemon live in Library/LaunchDaemons and still use the Endpoint Security framework?
Topic:
App & System Services
SubTopic:
Core OS
Tags:
Endpoint Security
Code Signing
Service Management
When I install my application, it installs fine and everything works alongwith all the system level daemons but when I reboot the system, none of my daemons are getting launched and this happens only on MacOS 15x, on older version it is working fine.
In the system logs, I see that my daemons have been detected as legacy daemons by backgroundtaskmanagementd with Disposition [enabled, allowed, visible, notified]
2025-01-13 21:17:04.919128+0530 0x60e Default 0x0 205 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] Type: legacy daemon (0x10010)
2025-01-13 21:17:04.919128+0530 0x60e Default 0x0 205 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] Flags: [ legacy ] (0x1)
2025-01-13 21:17:04.919129+0530 0x60e Default 0x0 205 0 backgroundtaskmanagementd: [com.apple.backgroundtaskmanagement:main] Disposition: [enabled, allowed, visible, notified] (0xb)
But later, it backgroundtaskmanagementd decides to disallow it.
2025-01-13 21:17:05.013202+0530 0x32d Default 0x4d6 89 0 smd: (BackgroundTaskManagement) [com.apple.backgroundtaskmanagement:main] getEffectiveDisposition: disposition=[enabled, disallowed, visible, notified], have LWCR=true
2025-01-13 21:17:05.013214+0530 0x32d Error 0x0 89 0 smd: [com.apple.xpc.smd:all] Legacy job is not allowed to launch: <private> status: 2
Is there anything changed in latest Mac OS which is causing this issue? Also what does this status 2 means. Can someone please help with this error?
The plist has is true
Purpose
I want to use launchd to run a shell script asynchronously every minute, but I'm encountering an issue where the job does not run, and I receive the error "Bootstrap failed: 5: Input/output error". I need help identifying the cause of this issue and how to configure launchd correctly.
What I've done
Created the shell script (test_ls_save.sh)
The script is designed to list the contents of the desktop and save the output to a specified directory.
#!/bin/bash
DATE=$(date +%Y-%m-%d_%H-%M-%S)
SAVE_DIR=/Users/test/Desktop/personal/log_gather
FILE_NAME="ls_output_$DATE.log"
ls ~/Desktop > "$SAVE_DIR/$FILE_NAME"
echo "ls output saved to $SAVE_DIR/$FILE_NAME"
File permissions (ls -l output): -rwxr-xr-x 1 test staff 1234 Feb 17 10:00 /Users/test/Desktop/personal/log_gather/exec/test_ls_save.sh
Created the launchd plist file (com.test.logTest.plist)
The plist file is configured to execute the shell script every minute.
<key>Label</key>
<string>com.test.logTest</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
/Users/test/Desktop/personal/log_gather/exec/test_ls_save.sh
</array>
<key>StartInterval</key>
<integer>60</integer> <!-- Run every minute -->
File permissions (ls -l output): -rwxr-xr-x 1 test staff 512 Feb 17 10:00 /Users/test/Library/LaunchAgents/com.test.logTest.plist
Ran the job with launchctl
I used the following command to load the plist file into launchd:
sudo launchctl bootstrap gui/$(id -u) /Users/test/Library/LaunchAgents/com.test.logTest.plist
pc spec
MacBook Pro
Apple M1
16 GB RAM
macOS 15.3 (Build 24D60)
what I know
The configuration has been set, but the launchd job is not running every minute as expected.
I don't believe there is a mistake with the path.
When I check the job using launchctl list, the job does not appear in the list.
I don't know where the error log files are supposed to be. I checked /var/log/system.log, but there are no error logs.
The .sh file runs fine by itself, but it cannot be executed via launchctl.
Want to ask
What could be the cause of the launchd job not running as expected?
Also, is there a way to check where the logs are being output?
If there is an error in the plist file configuration, which part should be modified?
Specifically, what improvements should be made regarding environment variables and path settings?
If my information is not enough, please tell me what is not enough!
Hi all,
Our company has an application that runs on several machines, this app is launched via a deamon that keeps it alive.
One of the feature of this app, is to start a headless electron application to run some tests. When spawning this electron application with the new arm64 OS, we are getting this issue:
Silent Test Agent Worker exited with code: 133
[ERROR] [75873:0205/135842.347044:ERROR:mach_port_rendezvous.cc(384)] bootstrap_look_up com.hivestreaming.silenttestagent.MachPortRendezvousServer.1: Permission denied (1100)
[ERROR] [75873:0205/135842.347417:ERROR:shared_memory_switch.cc(237)] No rendezvous client, terminating process (parent died?)
[ERROR] [75872:0205/135842.347634:ERROR:mach_port_rendezvous.cc(384)] bootstrap_look_up com.hivestreaming.silenttestagent.MachPortRendezvousServer.1: Permission denied (1100)
[ERROR] [75872:0205/135842.347976:ERROR:shared_memory_switch.cc(237)] No rendezvous client, terminating process (parent died?)
Both application (main app and electron one) are signed and notarized, but it seems that there is some other permission issue.
If we run the electron application manually, all runs as expected.
I added the crash report as attachment
CrashReport.log
Hi! I've been developing iOS and macOS apps for many years, but now I am looking to dive into smth i have never touched before, namely privileged helpers, and i am struggling hard trying to find my footing.
Here’s my use case: I have a CLI tool that requires elevated privileges. I want to create a menu bar app that can interact with this tool, but I’m struggling to find solid documentation or examples of how to accomplish this using SMAppService. I might just be missing something obvious.
If anyone could point me toward relevant documentation, examples, articles, tutorials, or even a WWDC session that covers running privileged helpers with SMAppService, I would greatly appreciate it.
Thanks in advance!
Hi,
On macOS Sonoma and earlier versions, I used my script along with a LaunchDaemon to continuously record my screen.
However, after upgrading to macOS Sequoia, the LaunchDaemon no longer works for screen recording. It only works when I use a LaunchAgent.
For my workflow, using a LaunchDaemon and running the ffmpeg process as root is much more efficient than running it as a regular user. Does anyone know how to run a script in the background using a LaunchDaemon on macOS Sequoia?
Here are my LaunchDaemon plist and script:
LaunchDaemon plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key> <string>local.ScreenRecord</string>
<key>Disabled</key> <false/>
<key>RunAtLoad</key> <true/>
<key>KeepAlive</key> <true/>
<key>Nice</key>
<integer>-20</integer>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/usr/local/distrib/record.bash</string>
</array>
</dict>
</plist>
Script
## !!! START CONFIGURATION !!!
#
FFMPEG_LOC="/usr/local/distrib/ffmpeg"
FFMPEG_INPUT="-hide_banner -f avfoundation -capture_cursor 1 -pixel_format uyvy422"
FFMPEG_VSET="-codec libx264 -r 22 -crf 26 -preset veryfast -b:v 5M -maxrate 7M -bufsize 14M"
TIME_REC="-t 600"
FOLDER_REC="/usr/local/distrib/REC/"
#
## !!! END CONFIGURATION !!!
#
# Find number id monitor
MON_ID=$($FFMPEG_LOC -hide_banner -f avfoundation -list_devices true -i "" 2>&1 | awk -F'[]|[]' '/Capture\ screen/ {print $4}')
#
if [ -n "$MON_ID" ]
then
# Time for name
DATE_REC=$(date +"%m-%d-%Y_%H-%M-%S")
# Number of output video file
OUTPUT_NUM=0
# Full command to record
FFMPEG_FULL_COMMAND=""
for MON_NUM in $MON_ID
do
FFMPEG_FULL_COMMAND=""$FFMPEG_FULL_COMMAND" "$FFMPEG_INPUT" -i "$MON_NUM" "$FFMPEG_VSET" "$TIME_REC" -map "$OUTPUT_NUM" "$FOLDER_REC""$DATE_REC"_Mon"$MON_NUM".mkv"
let OUTPUT_NUM=$OUTPUT_NUM+1
done
$FFMPEG_LOC $FFMPEG_FULL_COMMAND
else
echo "No monitors"
sleep 5
fi
I'm exploring using a handful of frameworks to share code between macOS apps. However, one of these frameworks needs privilege to function. The main app has a helper tool utilizing SMAppService. However, I can't work out if there's a feasible way to use that helper tool to support the framework dependency. Should I be creating a second helper tool for the framework instead? Or am I barking up the wrong tree?
Thanks!
Hello,
My team has developed a DNS proxy for macOS. We have this set up with a system extension that interacts with the OS, and an always-running daemon that does all the heavy lifting. Communication between the two is DNS request and response packet traffic.
With this architecture what are best practices for how the system extension communicates with a daemon?
We tried making the daemon a socket server, but the system extension could not connect to it.
We tried using XPC but it did not work and we could not understand the errors that were returned.
So what is the best way to do this sort of thing?
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
XPC
System Extensions
Network Extension
Service Management
Could not launch “App Name”
Domain: IDELaunchErrorDomain
Code: 20
Recovery Suggestion: LaunchServices has returned error -54. Please check the system logs for the underlying cause of the error.
User Info: {
DVTErrorCreationDateKey = "2024-12-27 12:16:34 +0000";
DVTRadarComponentKey = 113722;
IDERunOperationFailingWorker = IDELaunchServicesLauncher;
}
The operation couldn’t be completed. (OSStatus error -54.)
Domain: NSOSStatusErrorDomain
Code: -54
User Info: {
"_LSFunction" = "_LSOpenStuffCallLocal";
"_LSLine" = 4224;
}
our app has a helper to perform privileged operations.
previously that helper was installed via SMJobBless() into the /Library/LaunchDaemons/ and /Library/PrivilegedHelperTools/
we also had a script that would install the helper from the command-line, which was essential for enterprise users that could not manually install the helper on all their employee's Macs. the script would copy the files to their install location and would use launchctl bootstrap system as the CLI alternative to SMJobBless(). the full script is here: https://pastebin.com/FkzuAWwV
due to various issues with the old SMJobBless() approach we have ported to helper to the new SMAppService API where the helpers do not need to be installed but remain within the app bundle ( [[SMAppService daemonServiceWithPlistName:HELPER_PLIST_NAME] registerAndReturnError:&err] )
however, we are having trouble writing a (remote-capable) CLI script to bootstrap the new helper for those users that need to install the helper on many Macs at once. running the trivial
sudo launchctl bootstrap system /Applications/MacUpdater.app/Contents/Library/LaunchDaemons/com.corecode.MacUpdaterPrivilegedInstallHelperTool2.plist
would just result in a non-informative:
Bootstrap failed: 5: Input/output error
various other tries with launchctl bootstrap/kickstart/enable yielded nothing promising.
so, whats the command-line way to install a SMAppService based helper daemon? obviously 'installing' means both 'registering' (which we do with registerAndReturnError in the GUI app) and 'approving' (which a GUI user needs to manually do by clicking on the notification or by going into System Settings).
thanks in advance!
p.s. we wanted to submit this as a DTS TSI, but those are no longer available without spending another day on a reduced sample projects. words fail me.
p.p.s. bonus points for a CLI way to give FDA permissions to the app!
Topic:
App & System Services
SubTopic:
Core OS
Tags:
Entitlements
Service Management
Command Line Tools
Hi, I'm in the process of creating an App + Helper Tool combo application, and depending on the necessity of root privileges, I'm setting up two paths in the app:
If root privileges are not necessary, I'm using SMJobSubmit rather directly:
var submissionError: Unmanaged<CFError>?
let submissionResult = SMJobSubmit(kSMDomainUserLaunchd, plist, nil, &submissionError)
where plist contains these items:
Label=com.***.redactedApp.redacted,
ProgramArguments=[path/to/helper-tool, commandName, commandArg1, commandArg2]
RunAtLoad=1,
KeepAlive=0
and it works as necessary, and performs the operations.
Now, in the case of privilege escalation being necessary, this call becomes a bit more complex:
let authorization = SFAuthorization()
var authRef: AuthorizationRef?
do {
try authorization?.obtain(withRight: kSMRightModifySystemDaemons,
flags: [.extendRights, .interactionAllowed])
authRef = authorization?.authorizationRef()
} catch let error {
// Logging error
}
var submissionError: Unmanaged<CFError>?
let submissionResult = SMJobSubmit(kSMDomainSystemLaunchd, plist, authRef, &submissionError)
while using the same plist, same executable at the same path, same Label.
However, when using the second path, suddenly SMJobSubmit fails:
Error Domain=CFErrorDomainLaunchd Code=2 "(null)"
Now, naturally I headed over to system logs in Console.app, and this is the weirdest - there is nothing suspicious near the log item I submit with the above error from the main application.
The tool is embedded in the Contents/MacOS folder. However, my problem is that anything that I can think of seems to lead to the same thought: it should be a problem in both cases, not just the privileged one.
Is there something extra that must be taken care of when using SMJobSubmit with privileged helper tools?
I couldn’t create Apple ID account for the past 6 days
Topic:
Community
SubTopic:
Apple Developers
Tags:
Accounts
Messages
Service Management
Safari Services
I’m developing an app on macOS where I want a daemon/agent to run only when the user explicitly triggers it using SMAppService. The goal is to start the daemon when needed, perform the required task, and then stop/unload it after completion. Additionally, if unload or unregister calls are missed, I want to ensure that the daemon doesn’t start automatically upon reboot. Instead, it should only run when a specific action is taken. What are the best practices and detailed methods for achieving this clean and controlled behavior?
’m developing an app on macOS where I want a daemon/agent to run only when the user explicitly triggers it using SMAppService. The goal is to start the daemon when needed, perform the required task, and then stop/unload it after completion. Additionally, if unload or unregister calls are missed, I want to ensure that the daemon doesn’t start automatically upon reboot. Instead, it should only run when a specific action is taken. What are the best practices and detailed methods for achieving this clean and controlled behavior?
Hi,
we are in the process of exploring how to create an installer for our array of apps.
We have come to the conclusion that regular .pkg installers produced by pkgbuild and productbuild are unfulfilling of our expectations. [1]
Regardless, our installer needs to place files at privileged locations (/Library/Application Support) so we are looking into how to best solve this problem, with the user having
the largest clarity on what they are about to do (so no shady "wants to make changes" dialogs)
the least steps to do to install these files in the right place (so no targeted NSSavePanel-s)
Now, we have done our light reading via some nicely collected posts on the topic (https://forums.developer.apple.com/forums/thread/708765 for example) and the single missing option in the list of privilege escalation models seems to be a one-time privilege escalation from a GUI app.
Our reasons for declaring so:
AuthorizationExecuteWithPrivileges is long deprecated and we are trying to build a futureproof solution
NSAppleScript is just putting up a shady ("wants to make changes") dialog when trying something like this:
$ osascript -e "set filePath to \"/Library/Application Support\"" -e "do shell script \"touch \" & the quoted form of filePath & \"/yyy.txt\" with administrator privileges"
Is there another way to request a one-time authorization from the admin to perform such a simple operation as copying a file to a protected location?
I know it's possible to externalize and internalize Authorization Rights, but they are just an interface to create extra rights and use them as barriers, because they don't actually pass the required right to further operations based on this documentation.
Using SMAppService to register a daemon, which has to be manually allowed by the user adds a lot to the complexity of this installation process, and is something we would like to avoid if possible. (And it's also not the right security model if we want to be honest - we don't want ongoing administrator rights and a daemon)
Is there something we haven't taken into consideration?
[1] preinstall scripts run after the choices are presented during installation and we would need advanced logic (not the limited JavaScript system/files API provided by Installer JS) - plus, the GUI is obviously very limited in a .pkg :(