15. Services

Services are long-running applications designed to run in the background without user intervention and that are started automatically when the OS boots. InstallBuilder includes some actions to manage Windows and Linux services.

15.1. Linux Services

<addUnixService>
  <program>/path/to/script</program>
  <name>myservice</name>
</addUnixService>

The provided <program> must be a valid init script. As a basic example of code you could use is:

#!/sbin/sh

# chkconfig:        235 30 90
# description: your description

start () {
    # Put here the command to start your application
}

stop () {
    # Put here the command to stop your application
}

case "$1" in
start)
        start
        ;;
stop)
        stop
        ;;
restart)
        stop
        sleep 1
        start
        ;;
*)
        echo "Usage: $0 { start | stop | restart }"
        exit 1
        ;;
esac

exit 0

You can find other examples under /etc/init.d/ in a Linux installation.

<removeUnixService>
  <name>myservice</name>
</removeUnixService>

15.2. Windows Services

<createWindowsService>
  <program>${installdir}/myapp.exe</program>
  <programArguments></programArguments>
  <serviceName>myservice</serviceName>
  <displayName>My Service</displayName>
  <startType>auto</startType>
  <description>My Sample Service</description>
  <dependencies></dependencies>
  <account></account>
  <password></password>
</createWindowsService>

This will cause a service identified by <serviceName> and with display name <displayName> to be created. When starting, myapp.exe will be run from the application installation directory.

<startType> specifies that the service should be started along with operating system. It takes one of the following values:

  • auto - automatically start the service when the operating system is restarted.
  • manual - service does not start with the operating system, but can be manually started from the control panel and using the API
  • disabled - service does not start with the operating system and it cannot be manually started from the control panel or using the API.

By default, the service will be run as the system user. In order to run the service under a specific account, the <account> and <password> fields need to contain a valid user and password.

<deleteWindowsService>
  <serviceName>myservice</serviceName>
  <displayName>My Service</displayName>
</deleteWindowsService>

Deletes the service identified by <serviceName> and with the display name <displayName>. Both fields are used for identification of services on Microsoft Windows.

A service is stopped before deletion if it is currently running.

<startWindowsService>
  <serviceName>myservice</serviceName>
  <displayName>My Service</displayName>
  <delay>15000</delay>
</startWindowsService>

Starts the service identified by <serviceName> and with the display name <displayName>. Both fields are used for identification of services on Microsoft Windows.

<delay> specifies the number of milliseconds to wait for the service to start.

<stopWindowsService>
  <serviceName>myservice</serviceName>
  <displayName>My Service</displayName>
  <delay>15000</delay>
</stopWindowsService>

<delay> specifies amount of milliseconds to wait for the service to stop.

<restartWindowsService>
  <serviceName>myservice</serviceName>
  <displayName>My Service</displayName>
  <delay>15000</delay>
</restartWindowsService>

Stops service identified by <serviceName> and with display name <displayName>. Both fields are used for identification of services on Microsoft Windows.

<delay> specifies amount of milliseconds to wait for the service to stop and start.

InstallBuilder also provides a rule to check the status/existence of Windows services, <windowsServiceTest>. This can be used for example to create a service, but only if it does not already exist:

<createWindowsService>
  <program>${installdir}/myService.exe</program>
  <programArguments></programArguments>
  <serviceName>myservice</serviceName>
  <displayName>My Service</displayName>
  <startType>auto</startType>
  <description>My Service</description>
  <dependencies></dependencies>
  <account>bitrock</account>
  <password>mySecRetPassword!!</password>
  <ruleList>
    <windowsServiceTest service="myservice" condition="not_exists"/>
  </ruleList>
</createWindowsService>

InstallBuilder also provides an automatic way of generating unique Windows service names following a specified pattern. This is useful for situations in which you need to install multiple services.

<getUniqueWindowsServiceName>
  <serviceName>foo</serviceName>
  <displayName>My Foo service</displayName>
  <selectedDisplayNameVariable>newDisplayName</selectedDisplayNameVariable>
  <selectedServiceNameVariable>newServiceName</selectedServiceNameVariable>
</getUniqueWindowsServiceName>

<createWindowsService>
   <program>${installdir}/myService.exe</program>
   <programArguments></programArguments>
   <serviceName>${newServiceName}</serviceName>
   <displayName>${newDisplayName}</displayName>
   <startType>auto</startType>
   <description>My Service</description>
   <dependencies></dependencies>
   <account>bitrock</account>
   <password>mySecRetPassword!!</password>
</createWindowsService>

If the service foo already exists, InstallBuilder will pick a new service name, foo-1, if that is taken as well, foo-2, foo-3 and so on… until a valid unique name is found, storing the new names in the provided <selectedDisplayNameVariable> and <selectedServiceNameVariable>.

Using regular binaries as Windows services

Services in Microsoft Windows require binaries created especially for running as a service and need to properly support being stopped, started, paused and resumed.

In some cases it is necessary to run binaries that were not created for running as a service. It is possible to use third party tools to run applications as services. This way any application or script can be used as a Windows service. There are multiple solutions for running any application as a script. Microsoft provides srvany.exe tool that can be used for creating services from any application. It is described on Microsoft’s website: http://support.microsoft.com/kb/137890. The binary simply runs itself as a service and starts application as child process. However, srvany cannot be easily redistributed due to licensing issues.

Another tool is nssm.exe. It is a single file application that can be redistributed with your installer. The binary can be downloaded from http://nssm.cc/.

The first step is to add nssm.exe to the installer’s payload. It can be done as part of existing component or as new component:

<component>
  <name>nssm</name>
  <description>nssm</description>
  <canBeEdited>0</canBeEdited>
  <selected>1</selected>
  <show>0</show>
  <folderList>
    <folder>
      <description>nssm</description>
      <destination>${installdir}</destination>
      <name>nssm</name>
      <platforms>windows</platforms>
      <distributionFileList>
        <distributionFile>
          <origin>/path/to/nssm.exe</origin>
        </distributionFile>
      </distributionFileList>
    </folder>
  </folderList>
</component>

The next step is to add actions to the post-installation step that creates a service. The service name is set to the servicename variable. The nssm.exe install "${servicename}" "${installdir}/myapp.exe" command creates and runs the service. Finally the nssm.exe set "${servicename}" Start "SERVICE_AUTO_START" command sets the value for a service pararameter, in this case the service’s startup type.

<postInstallationActionList>
  <setInstallerVariable>
    <name>servicename</name>
    <persist>1</persist>
    <value>IBSampleService</value>
  </setInstallerVariable>
  <runProgram>
    <runAs>Administrator</runAs>
    <program>${installdir}/nssm.exe</program>
    <programArguments>install "${servicename}" "${installdir}/myapp.exe"</programArguments>
    <workingDirectory>${installdir}</workingDirectory>
  </runProgram>
  <runProgram>
    <runAs>Administrator</runAs>
    <program>${installdir}/nssm.exe</program>
    <programArguments>start "${servicename}" "SERVICE_AUTO_START"</programArguments>
    <workingDirectory>${installdir}</workingDirectory>
  </runProgram>
</postInstallationActionList>

When the application is uninstalled, <deleteWindowsService> needs to be called to delete the service.

<preUninstallationActionList>
  <deleteWindowsService>
    <abortOnError>0</abortOnError>
    <displayName></displayName>
    <serviceName>${servicename}</serviceName>
  </deleteWindowsService>
</preUninstallationActionList>

15.3. OS X Services

 <createOSXService>
   <groupname>wheel</groupname>
   <username>daemon</username>
   <program>${installdir}/myService.run</program>
   <programArguments></programArguments>
   <scope>user</scope>
   <serviceName>myService</serviceName>
 </createOSXService>

 <deleteOSXService>
   <serviceName>myService</serviceName>
 </deleteOSXService>

Deletes a service on Mac OS X identified by <serviceName>, which contains the unique identifier of services for Mac OS X. The service is stopped before deletion if it is currently running.

 <stopOSXService>
   <serviceName>myService</serviceName>
 </stopOSXService>

This stops service on Mac OS X identified as serviceName. It is the unique identifier of services for Mac OS X.

 <startOSXService>
   <serviceName>myService</serviceName>
 </startOSXService>

This starts service on Mac OS X identified as serviceName. It is the unique identifier of services for Mac OS X.

[Note]

OS X service management actions are only supported from OS X 10.4 and newer

[Note]

As a prerequisite, the program to be registered as a service must be compiled to run as a daemon

InstallBuilder also provides a rule to check the status of OS X services, <osxServiceTest>:

 <stopOSXService>
   <serviceName>myService</serviceName>
   <ruleList>
      <osxServiceTest service="myService" condition="is_running"/>
   </ruleList>
 </stopOSXService>

Adding an Application to the System Startup

There are multiple ways of launching an application at startup on OS X, and it can vary from version to version of the operating system. This section describes the most general/compatible ones:

  • Changing the user Preferences files: This is the approach followed when manually adding an application to the Startup items. To do this, add a new entry to the ~/Library/Preferences/loginwindow.plist file with the below format:
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>nameOfTheEntry</string>
    <key>ProgramArguments</key>
    <array>
      <string>/some/path/to/the/program.run</string>
      <string>/Applications/BitRock InstallBuilder for Qt 7.2.5/autoupdate/runtimes/autoupdate-osx.a\
pp</string>
    </array>
    <key>KeepAlive</key>
    <true/>
    <key>Hide</key>
    <true/>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>
  • Creating a launchd daemon: This approach is the preferred one when you do not have to support OS X versions below 10.4. Using this method you still need to create a .plist file in the same format as the one described in the previous method. Once you have it created, you just have to move it to /Library/LaunchDaemons/:
 $> sudo cp startup.plist /Library/LaunchDaemons/com.yourCompany.yourProgram.plist

Following the same naming in the target file is important to avoid conflicts in the future.

After restarting the machine, the new process should be running.

The code to automate this method in InstallBuilder would be:

  <writeFile>
    <path>${system_temp_directory}/your.plist</path>
    <encoding>utf-8</encoding>
    <text><![CDATA[
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>nameOfTheEntry</string>
    <key>ProgramArguments</key>
    <array>
      <string>/some/path/to/the/program.run</string>
      <string>/Applications/BitRock InstallBuilder for Qt 7.2.5/autoupdate/runtimes/autoupdate-osx.app</string>
    </array>
    <key>KeepAlive</key>
    <true/>
    <key>Hide</key>
    <true/>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>
]]></text>
  </writeFile>
  <copyFile>
    <origin>${system_temp_directory}/your.plist</origin>
    <destination>/Library/LaunchDaemons/com.yourCompany.yourProgram.plist</destination>
  </copyFile>
  • Creating a Startup Item: If your application requires compatibility with OS X 10.3 and earlier, this is the only available approach. The steps to follow are:

Create a directory under /Library/StartupItems with the name of the startup item:

 $> sudo mkdir /Library/StartupItems/yourItem

Create an executable with the same name of the directory. This executable can be just a bash script wrapping the your binary:

 $> sudo touch /Library/StartupItems/yourItem/yourItem

The yourItem script should implement the below functions (you can leave the body blank if they are not applicable to your startup item):

#!/bin/sh
. /etc/rc.common

StartService ()
{
    /Applications/yourApplication-1.0/ctl.sh start
}

StopService ()
{
    /Applications/yourApplication-1.0/ctl.sh stop
}

RestartService ()
{
    /Applications/yourApplication-1.0/ctl.sh graceful
}

RunService "$1"

Create a .plist file named StartupParameters.plist with some information about your item:

<plist version="1.0">
  <dict>
     <key>Description</key>
     <string>My Application v1.0</string>
     <key>OrderPreference</key>
     <string>None</string>
     <key>Provides</key>
     <array>
        <string>yourItem</string>
     </array>
  </dict>
</plist>

It can be tested by executing:

 $> sudo /sbin/SystemStarter start "yourItem"