/* Code Musings */

Interprocess Communication in BB10

One of the most recent features in BB10 was the addition of Headless Services. A headless application (or service, as it’s called) is one without a graphical interface, or head, for the user to interact with. It’s generally a slim body of code that runs in the background as an event handler on behalf of the application. An example of this is the Facebook application, where the background service handles incoming events and messages without the need to have the Facebook UI open.

Communication between the two processes can be complex. Since the service and UI application are two separate processes, a form of Interprocess Communication (IPC) is needed. The QNX website lists a few examples of IPC, and each one has it’s fair share of Pro’s and Con’s. However, in this post, I’ll be detailing the use of domain sockets, or as they’re call in the Windows world: named pipes.

Data Transmission:
Domain sockets (or local sockets) function like a regular sockets but with the additional benefits of having file-like permissions. Thus, this secures the communication channel from the prying eyes of other applications.

The easiest way of implementing such a channel is through Qt’s QLocalSocket and QLocalServer classes.

On the UI application end, the client connects to the server using the same Identifier.

Establishing this communication channel is not the hard part. What becomes difficult is the format of data and concurrency. One such issue is what to do when an service is not running during the time the UI application wants to connect. While developing the ICQ application for BB10, I ran into this issue often. The solution was to kick the service by sending it a START invoke request:

A word of caution: don’t spam the service with an invoke action. The service process will be launched by the system, which may take some time. In the ICQ application, I limited this to once every 15 seconds. Generally, if the service does not create the domain socket within that time span, there is a larger problem or a subsequent invoke may be required. Once the service is kicked and running, it should immediately create the domain socket and the UI application will connect.

Formatting Data:
The next complex topic is data transmission over this communication channel. A common format between the service and UI application is needed and I highly recommend using JSON. Cascades provides an efficient way of converting QVariant types into JSON through the JsonDataAccess object. The following is an example of serialization to and from JSON:

There are other ways of serializing, but I found this one easiest to use and debug. The down side of this approach is that the message decoding and marshaling is a manual process. Both sides need to know what type of data is being transmitted and how to parse it. It can be verbose and tedious.

An alternative that I have recently begun to explore is remote signals and slots. A small number of libraries currently exist, such as QtxRPCPeer and qt-remote-signals to name a few. I have not yet used these libraries, but the concept itself looks promising.

Leave a Reply