Since Brew 1.x, applications have been able to share data via the file system by putting files in the shared directory. Later versions of Brew improve upon this convention by providing access control lists (ACLs), permitting modules to share access to their private directories. While this has been an acceptable means to share large quantities of data between applications, it can have stiff performance penalties, as applications must read and write the data being shared to the flash file system.
In Brew 3.x, Qualcomm introduced the IFIFO interface, which as its name suggests, is a first-in-first-out queue for interapplication communication. Applications using IFIFO specify the location of the fifo as they open it using a file path preceded by the string fifo:/, i.e., fifo:/shared/rayapp or fifo:/~0x123456/rayapp. The first example denotes a fifo in the shared file system that can be accesed by any application; the latter a fifo in a specific module's directory that can only be accessed by applications that have the appropriate entry in their ACL.
Once a FIFO is opened, it can can be read from or written to depending on the access mode they specify when opening the fifo. For example, to open the fifo located at /shared/rayapp for reading and writing, I would refer to the fifo as fifo:/shared/rayapp?mode=rw, like this:
result = ISHELL_CreateInstance( pMe->a.m_pIShell, AEECLSID_FIFO, (void **)&pMe->pififo );
if ( result == SUCCESS )
result = IFIFO_Open( pMe-<pififo, "fifo:/shared/rayapp?mode=rw" );
// handle result errors here.
Once open, the using the fifo is just like using any other Brew socket. You must see if you can write to the fifo by calling IFIFO_Writable
with a callback, and in your callback, invoke IFIFO_Write
. Similarly, to read data, set a callback using IFIFO_Readable and read the data using IFIFO_Read
, looking for ISOURCE_WAIT, ISOURCE_ERROR
, and ISOURCE_END
values, indicating that all of the data has been read, an error has occured, or the writer has closed the fifo, respectively.
You can also set and query the fifo's buffer size (within reason) using IFIFO_SetBufSize and IFIFO_GetBufSize. Equally useful is IFIFO_GetBufUsed, which returns the number of bytes used in the buffer.
When using a fifo, two questions come to mind: in what format should the data be, and how should listeners wait for the data? The answer to the former is largely application-dependent, but of course you should consider platform-agnostic types such as media types, XML, and YAML, to make the most of decoupling between your applications.
|Figure 1. Picture This: Drawing lines using different Pens.|
The second question also depends on the nature of your application, but in practice an approach coupling an event with a specific fifo can work well. When a client application needs to request a service of the serving application, it registers an event and invokes ISHELL_SendEvent to the serving application. The serving application registers the same event on module load, then responds to the event by opening the established fifo for reading and launches to the background. The client application is then free to write its request to the fifo, and the serving application can respond via events or a second fifo as appropriate (see Figure 1).
Brew's Come a Long Way, Baby
Interapplication communication has come a long way since the lowly shared file and mutually agreed upon event found in the first versions of Brew. Using either URLs for simple data types or fifos for complex data blocks, it's now possible to create sophisticated client-server relationships between applications in Brew.