At 12:24 +0100 30/9/08, Tim Schooley wrote:
Is nobody able to advise on this type of scenario?
Alas, if there was an easy answer I would've answered earlier. This is a known limitation of launchd's current architecture. There's already a bug to cover this <rdar://problem/5476420> but I don't have information to share about when it might be addressed. I've seen two broad classes of workaround: A. application specific -- Code your agent to listen for upgrade notifications. That is, rather than try to have your installer find, unload, and reload each agent, have it broadcast a notification that instructs to agents to unload. There are two aspects to this: - communication -- If your agents are all talking to a common piece of code (for example, a daemon or a kext), you can have that common code send the notification to the agent via its standard communications channel. This could be as simple as having your daemon quit (and hence drop its connection to all of the agents) and having the agent respond to a dropped connection by quitting (and being relaunched by its per-user launchd). If your agents don't all talk to a common piece of code, you'll need to use some other notification mechanism (perhaps <x-man-page://3/notify> or CFNotificationCenter with kCFNotificationPostToAllSessions). - quit vs unload -- In most cases you can just overwrite your agent from your installer and then have the agent quit. launchd will relaunch your agent from the new code. There are some gotchas here: * Your old and new agents must be sufficiently compatible on disk to avoid problems. For example, if your new agent removes a .strings file that your old agent relies on, you could run into transient and very hard to debug problems. * You won't be able to change your agent's property list file (because each per-user launchd has cached its contents when the job was loaded). If these are a problem, your agent will need to be smarter. For example, it could use launchctl to unload and then reload itself. Yeah, that gets ugly fast )-: Finally, this option has one limitation for which there is no good workaround: if there are two GUI login sessions when you first install, you can't get the agent running in the background session. This works in the upgrade case (because you have already have an agent running in the background session to help out) but in the first install case you're SOL. B. bootstrap switch -- Another option is to explicitly talk to a given per-user launchd by switching your bootstrap namespace. You can find out all the GUI login sessions using the techniques from QA1133 "Determining console user login status". <http://developer.apple.com/qa/qa2001/qa1133.html> You can use launchctl's bsexec command to run commands in a different login session. Thus, you can explicitly unload the job from all per-user launchds, do your install, and then reload it. * * * Neither of these solutions is ideal. Both are hard to implement and entail a certain amount of compatibility liability. If I had to choose between them, I'd probably go for A because it's likely to be the most compatible. Overall, I recommend that you carefully weigh these options against the cop-out solution of forcing a restart. While I agree that it is not very Mac like, it is easy to implement and will be very compatible. S+E -- Quinn "The Eskimo!" <http://www.apple.com/developer/> Apple Developer Relations, Developer Technical Support, Core OS/Hardware