Creating a Launch Agent (per user) on demand when client app is open
Hello, I would like to create a Launch Agent that would start on demand when my bundle app requires it. I have it currently implemented like below which monitors a specific path for existence of a file. This works ok for one user logged in. If I there are more users logged via Fast User Switching the OS tends to open the service for different user, not the one that’s currently using my app. That’s because two users are now monitoring the same path and the OS isn’t sure in which user’s context the service should run. Also my bundle app has LSMultipleInstancesProhibited set to true, so it isn’t allowed to run two instances at once. But if User A opens my app and there is a User B logged in, the service may open for User B (even the file from the plist was created by User A and User B hasn’t touched my app). Therefore I need a solution that would allow my client app to open the service for the same user it runs as. And if I close the app for User A, switch to User B and start the client, the service would now open for User B. Thanks, Peter <?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>KeepAlive</key> <dict> <key>PathState</key> <dict> <key>/Users/Shared/Company/Service.txt</key> <true/> </dict> </dict> <key>Label</key> <string>com.company.service</string> <key>Program</key> <string>/Users/Shared/Company/Service</string> <key>MachServices</key> <dict> <key>com.company.service</key> <true/> </dict> </dict> </plist>
On 15 Jan 2015, at 12:25, Piotr Panasewicz <piotr.panasewicz@mac.com> wrote:
I would like to create a Launch Agent that would start on demand when my bundle app requires it.
I'm not sure I understand your requirements correctly, but the best way to achieve the goal as summarised by the above sentence is to have the agent listen on an IPC channel and have the app send a message on that channel. And the IPC channel of choice these days is XPC, via the very nice NSXPCConnection API. Share and Enjoy -- Quinn "The Eskimo!" <http://www.apple.com/developer/> Apple Developer Relations, Developer Technical Support, Core OS/Hardware
Hi Piotr, This sounds like a good use case for an XPC service. The service would ship in your app's bundle, and each instance of your app would have a private instance of the service that it talked to, and that instance would run with the same uid as your app. More here: http://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSys... -damien On 15 Jan, 2015, at 04:25, Piotr Panasewicz <piotr.panasewicz@mac.com> wrote:
Hello,
I would like to create a Launch Agent that would start on demand when my bundle app requires it. I have it currently implemented like below which monitors a specific path for existence of a file. This works ok for one user logged in. If I there are more users logged via Fast User Switching the OS tends to open the service for different user, not the one that’s currently using my app. That’s because two users are now monitoring the same path and the OS isn’t sure in which user’s context the service should run.
Also my bundle app has LSMultipleInstancesProhibited set to true, so it isn’t allowed to run two instances at once. But if User A opens my app and there is a User B logged in, the service may open for User B (even the file from the plist was created by User A and User B hasn’t touched my app).
Therefore I need a solution that would allow my client app to open the service for the same user it runs as. And if I close the app for User A, switch to User B and start the client, the service would now open for User B.
Thanks, Peter
<?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>KeepAlive</key> <dict> <key>PathState</key> <dict> <key>/Users/Shared/Company/Service.txt</key> <true/> </dict> </dict> <key>Label</key> <string>com.company.service</string> <key>Program</key> <string>/Users/Shared/Company/Service</string> <key>MachServices</key> <dict> <key>com.company.service</key> <true/> </dict> </dict> </plist>
_______________________________________________ launchd-dev mailing list launchd-dev@lists.macosforge.org https://lists.macosforge.org/mailman/listinfo/launchd-dev
Hello Damien, Is it possible to do that without XPC? The problem is that code of the agent/service is rather multiplatform, it needs to work on Windows too, with the Windows version of the client. Of course we can separate implementation for each OS but right now the main difference of both is the way the service starts. I need an agent that would start on demand (like it is doing now by creating a file when I need it to run and deleting it, when I want it to shutdown). The only problem is that is sometimes starts as the other user which is logged in via fast user switching or VNC. Right now it works like this. I start my client app, the app creates the .txt file to start the agent and my app tells the agent to check if there are available updates to my client. Then the client closes and the agent starts the updater (the agent and the updater are a part of a redistributable package and on Mac they reside at fixed path: /Users/Shared/Company/redists/). The updater performs its task and hits back to the agent with a response that it finished and we can restart the client. The agent then starts the client. So as you see if the agent starts as a different user, the updater and the client will start for that user as well, not the one that initially clicked the client app. Thanks. The agent has a timeout implemented as well, so when it doesn’t receive any message for more than 30 seconds, it deletes the txt file and closes itself.
On 15 Jan 2015, at 17:56, Damien Sorresso <dsorresso@apple.com> wrote:
Hi Piotr,
This sounds like a good use case for an XPC service. The service would ship in your app's bundle, and each instance of your app would have a private instance of the service that it talked to, and that instance would run with the same uid as your app. More here:
http://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSys... -damien
On 15 Jan, 2015, at 04:25, Piotr Panasewicz <piotr.panasewicz@mac.com> wrote:
Hello,
I would like to create a Launch Agent that would start on demand when my bundle app requires it. I have it currently implemented like below which monitors a specific path for existence of a file. This works ok for one user logged in. If I there are more users logged via Fast User Switching the OS tends to open the service for different user, not the one that’s currently using my app. That’s because two users are now monitoring the same path and the OS isn’t sure in which user’s context the service should run.
Also my bundle app has LSMultipleInstancesProhibited set to true, so it isn’t allowed to run two instances at once. But if User A opens my app and there is a User B logged in, the service may open for User B (even the file from the plist was created by User A and User B hasn’t touched my app).
Therefore I need a solution that would allow my client app to open the service for the same user it runs as. And if I close the app for User A, switch to User B and start the client, the service would now open for User B.
Thanks, Peter
<?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>KeepAlive</key> <dict> <key>PathState</key> <dict> <key>/Users/Shared/Company/Service.txt</key> <true/> </dict> </dict> <key>Label</key> <string>com.company.service</string> <key>Program</key> <string>/Users/Shared/Company/Service</string> <key>MachServices</key> <dict> <key>com.company.service</key> <true/> </dict> </dict> </plist>
_______________________________________________ launchd-dev mailing list launchd-dev@lists.macosforge.org https://lists.macosforge.org/mailman/listinfo/launchd-dev
15 jan 2015 kl. 17:59 skrev Piotr Panasewicz <piotr.panasewicz@mac.com>:
Is it possible to do that without XPC?
Yes, you can have the agent listen on a localhost or unix domain socket: https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSy... https://developer.apple.com/library/mac/samplecode/SampleD/Introduction/Intr... -- Per Olofsson, IT-service, University of Gothenburg
Seems I will encounter the same issues I am having now with listening on localhost or socket port option. In my current implementation the agent sometimes starts as the second logged in user via fast user switching (so both sessions are GUI sessions and active at the time). So if I have an agent (with plist inside /Library/LaunchAgents, so it will work for each user logged in) monitoring localhost or the specific socket port, for which user the agent will run? Because both sessions are active and have GUI. How will I communicate with the one I want if the IPC between my app and the agent is base on one socket port 9977? If I run my app as User A I want the service to run only for the User A, not User B, or both. Peter
On 16 Jan 2015, at 09:11, Per Olofsson <per.olofsson@gu.se> wrote:
15 jan 2015 kl. 17:59 skrev Piotr Panasewicz <piotr.panasewicz@mac.com>:
Is it possible to do that without XPC?
Yes, you can have the agent listen on a localhost or unix domain socket:
https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSy...
https://developer.apple.com/library/mac/samplecode/SampleD/Introduction/Intr...
-- Per Olofsson, IT-service, University of Gothenburg
_______________________________________________ launchd-dev mailing list launchd-dev@lists.macosforge.org https://lists.macosforge.org/mailman/listinfo/launchd-dev
16 jan 2015 kl. 13:21 skrev Piotr Panasewicz <piotr.panasewicz@mac.com>:
Seems I will encounter the same issues I am having now with listening on localhost or socket port option.
In my current implementation the agent sometimes starts as the second logged in user via fast user switching (so both sessions are GUI sessions and active at the time). So if I have an agent (with plist inside /Library/LaunchAgents, so it will work for each user logged in) monitoring localhost or the specific socket port, for which user the agent will run? Because both sessions are active and have GUI. How will I communicate with the one I want if the IPC between my app and the agent is base on one socket port 9977? If I run my app as User A I want the service to run only for the User A, not User B, or both.
A unix domain socket listener can identify the UID of the connecting peer by using getpeereid() or LOCAL_PEERCRED. You can use this with a privileged listener which forks and executes tasks on behalf of the connecting peer, but I would not recommend going down that route unless you're comfortable writing privileged code. NSXPCConnection is a lot less work and secure by default. -- Per Olofsson, IT-service, University of Gothenburg
participants (4)
-
Damien Sorresso
-
Per Olofsson
-
Piotr Panasewicz
-
Quinn "The Eskimo!"