Sandboxed app to install a service?

I would like a sandboxed OSX app to install and run a service app.

Does anybody know how I have to proceed to achieve this?

The service app would do things like this:

  • check for updates
  • install and update and relaunch the main app
  • query a database for scheduled actions and execute them (like sending out emails at a specific moment, etc)
  • relaunch the main app after the user made changes to userinterface and database design
  • create regular backups
  • Main app and service app can communicate with each other
  • service app starts at system startup

According to the Mac Develop Library there seem to be different options:

  • XPC Services (managed by launchd), which offer privilege separation and run in their own sandbox
  • Using the NSTask class (like in the Sandboxkit’s OWSHell by Ohanaware), which inherits the sandbox of the process having created it.
  • LaunchAgents seems also to be possible

MBS has an example for XPC, but I was not able to make it work so far.
https://www.monkeybreadsoftware.net/module-servicemanagementmodulembs.shtml
https://www.monkeybreadsoftware.net/pluginpart-nsxpc.shtml

Valdemar did something here:
https://forum.xojo.com/12479-helper-apps-and-the-sandbox/p3#p97150

Ohanaware has OWShell in its sandbox kit.

So which way to go? Any recommendations, anyone?

[quote=188866:@Oliver Osswald]I would like a sandboxed OSX app to install and run a service app.

Does anybody know how I have to proceed to achieve this?

The service app would do things like this:

  • check for updates
  • install and update and relaunch the main app
  • query a database for scheduled actions and execute them (like sending out emails at a specific moment, etc)
  • relaunch the main app after the user made changes to userinterface and database design
  • create regular backups
  • Main app and service app can communicate with each other
  • service app starts at system startup

According to the Mac Develop Library there seem to be different options:

  • XPC Services (managed by launchd), which offer privilege separation and run in their own sandbox
  • Using the NSTask class (like in the Sandboxkit’s OWSHell by Ohanaware), which inherits the sandbox of the process having created it.
  • LaunchAgents seems also to be possible

MBS has an example for XPC, but I was not able to make it work so far.
https://www.monkeybreadsoftware.net/module-servicemanagementmodulembs.shtml
https://www.monkeybreadsoftware.net/pluginpart-nsxpc.shtml

Valdemar did something here:
https://forum.xojo.com/12479-helper-apps-and-the-sandbox/p3#p97150

Ohanaware has OWShell in its sandbox kit.

So which way to go? Any recommendations, anyone?[/quote]

I use Valdemar’s VDSC, but for less ambitious an agenda. The nice thing about it that basically the launch helper agent is a standard Xojo app. Carrying out the following tasks seems quite possible.

[quote]- check for updates

  • install and update and relaunch the main app
  • query a database for scheduled actions and execute them (like sending out emails at a specific moment, etc)
  • create regular backups
  • Main app and service app can communicate with each other
  • service app starts at system startup[/quote]

Main app and service app can communicate with IPC ; I do that in mine. From what you want to do, you cannot have the helper quit immediately after it launches the main app. You will have to have it quit when the main app quits.

That makes the relaunch a bit more intricate. You will need to have a procedure where the helper does not quit, and launches the main app again only after it has quit for good. Otherwise since on Mac two instances of the same app cannot normally run at the same time, it will not work.

The backup thing looks like a task you may want to keep in the main app, since accessing data from two different apps has its own challenges.

+1 for Valdemar’s code. Which works great except for stopping the service app. One problem will be that your service app needs to be outside of the main app for handling the update. I’m not sure if this is going to work for a sandboxed app.

What doesn’t work for you with the XPC? It IS a bit tricky. The bundle IDs of the 2 apps have to be the same. And removing the helper app only works with launchctl via Shell.

In fact, I do not need to quit the helper app, I just need to be sure it is no longer active once the user removes the main app. But if the helper is contained within the main app, then OSX won’t be able to launch the helper after a restart of the computer, right?

In addition to that I could add some code which is looking for the main app and then terminates itself, in case its parent is no longer there.

So I guess, I will try Valdemar’s solution. Which leads me to another question:

What is his “Helper Integrator” app actually doing? I understand that Valdemar can get some donation-ware bucks with it, but I do not like such blackboxes very much. Is it just adding some values to a plist file, or more?

@Oliver: hadn’t seen the “Helper Integrator”, so I haven’t needed it. Valdemar’s source code.

  1. Both apps need the same bundle ID.
  2. Make the helper app invisible with the usual plist change.
  3. Copy the helper app to the correct place (you need a script because the copy step crashes Xojo).
  4. Register the helper app with the code provided by Valdemar.
  5. Use my code in the other thread to deregister the helper app.

HTH

[quote=188879:@Beatrix Willius]<…>
HTH[/quote]
I think so, I’ll give it a try.
Vielen herzlichen Dank!

[quote=188879:@Beatrix Willius]Both apps need the same bundle ID.
Make the helper app invisible with the usual plist change.
Copy the helper app to the correct place (you need a script because the copy step crashes Xojo).
Register the helper app with the code provided by Valdemar.
Use my code in the other thread to deregister the helper app.[/quote]

Bundle IDs can be different. I have an app in the MAS that uses Valdemar’s code and it works with two different bundle IDs in the helper and the main app.

As far as I can see, It simply places the helper app inside the bundle of the main app /Library/LoginItems/ folder. It does not seem possible to do with Copy Files.

Thank you Michel, appreciate very much your help as well!

[quote=188883:@Michel Bujardet]Bundle IDs can be different. I have an app in the MAS that uses Valdemar’s code and it works with two different bundle IDs in the helper and the main app.
[/quote]

@ Michel: Do you have any experience on how to communicate between main app and helper, back and forth?

I have tried to use IPCSocket, but the helper fails to connect. I tried to use a path (socketfile) within the container’s Application Support, as well as a SpecialFolder.Temporary path, for the IPCSocket1.Path property.

This is in the Open Event handler of the helper app:

CommSocket1 = New CommSocket // subclassed IPCSocket If CommSocket1 <> Nil Then 'Dim p As String = App.Temp.Child(App.BundleID).NativePath Dim p As String = SpecialFolder.Temporary.Child(App.BundleID).NativePath CommSocket1.Path = p CommSocket1.Listen End If

And it results in a Errorcode 106 (InvalidStateError).

Apparently I do get the identical path in main app and in the helper, still the helper fails to listen and then the main app cannot connect. Here with a path to temporary folderitem:

[quote]26.05.15 18:25:26.492 com.osswald.assist002[1761]: ****** assist.app : App.Open : IPC Path: /private/var/folders/b0/jnshwx0x6x35tvz9ntwlnh8h0000gn/T/com.osswald.assist002/TemporaryItems/com.osswald.assist002
[/quote]

Main app and helper have both the same Bundle Identifier and both are sandboxed (I verified with RB App Checker Lite)

I’m stuck with this and hope anybody has an idea how helper and main app can communicate in a sandbox.

[quote=190057:@Oliver Osswald]@ Michel: Do you have any experience on how to communicate between main app and helper, back and forth?

I have tried to use IPCSocket, but the helper fails to connect. I tried to use a path (socketfile) within the container’s Application Support, as well as a SpecialFolder.Temporary path, for the IPCSocket1.Path property.

This is in the Open Event handler of the helper app:

CommSocket1 = New CommSocket // subclassed IPCSocket If CommSocket1 <> Nil Then 'Dim p As String = App.Temp.Child(App.BundleID).NativePath Dim p As String = SpecialFolder.Temporary.Child(App.BundleID).NativePath CommSocket1.Path = p CommSocket1.Listen End If

And it results in a Errorcode 106 (InvalidStateError).

Apparently I do get the identical path in main app and in the helper, still the helper fails to listen and then the main app cannot connect. Here with a path to temporary folderitem:

Main app and helper have both the same Bundle Identifier and both are sandboxed (I verified with RB App Checker Lite)

I’m stuck with this and hope anybody has an idea how helper and main app can communicate in a sandbox.[/quote]

I remember using IPCSocket a while ago for that in an experiment but have unfortunately not kept the code. Sorry. I don’t recall ever encountering error 106, though.

Another way consists simply in using the "hollow tree strategy " : a file that one app writes to for the other to read. After the file has been read it is deleted. In each app, use a timer to verify periodically if a new file is available to read with f.exists. Of course, it is slower.

[quote=190059:@Michel Bujardet]I remember using IPCSocket a while ago for that in an experiment but have unfortunately not kept the code. Sorry. I don’t recall ever encountering error 106, though.

Another way consists simply in using the "hollow tree strategy " : a file that one app writes to for the other to read. After the file has been read it is deleted. In each app, use a timer to verify periodically if a new file is available to read with f.exists. Of course, it is slower.[/quote]
Exactly, this is what I will try next. I have hoped not to re-invent the wheel, and to use Ipcsocket.

Thanks for the hint, have a good night!
Oliver