November 22, 2014
Hot Topics:

Inter-Application Communication in BREW

  • July 23, 2004
  • By Radu Braniste
  • Send Email »
  • More Articles »

This time, we will discuss inter-application communication—a rather strange topic taking into account the BREW environment, where small, standalone applications prevail. Once BREW becomes more mainstream and handhelds more powerful, applications tend to be more complex, leaving behind the old monolithic approach and making use of more sophisticated design choices.

That's why this article will try to answer questions such as:

  • How can two or more processes exchange information in BREW?
  • When should you use IAC? What are the design considerations?
  • How does one create and use services in BREW?

Why Do We Need Inter-Application Communication?

There are various reasons, usually implying design decisions.

The simplest case is when you need to pass/extract data to/from other applications (a suite of applications is a good example).

A more complex situation is a service; for example, an XML parser. There is little need for a parser to share its state (if any) with other processes. An extension fills the bill here, no doubt—an extension used by all the interested parties in this service.

Extensions in BREW are like "in-process" components in COM, being loaded in the space (context) of the caller. This means that our extension will have the same life span as the caller and every call to

IExtensionCls* e = 0;
ISHELL_CreateInstance(shell, AEECLSID_EXTENSION_CLS, (void **)&e);

should generate a new instance of IExtensionCls. There is no inter-application communication in this case, but rather a shared "execution model."

What happens if our service has to share state (a database, for example)? An extension doesn't fill the bill any more because there are obvious limitations, for example:

  • The extension should be a singleton in this case and COM singletons have well-known drawbacks [1]
  • All the memory allocated in an extension is tied to the caller context. Destroying the context (calling application) implicitly destroys the callee.
  • Raw pointers have to be passed over process boundaries—a technique allowed today but forbidden in future versions of BREW implementing memory protection between processes (the same happened in the transition fro Win16 to Win32, for example)

The best design in this case is to encapsulate the data in a process of its own, accessible via a well-known interface that can be modeled as an extension. Shortly, we will present such an example.

Background Applications

BREW 2.0 introduced a new kind of state for an application: background, in addition to active and suspended states. Background applications are discussed in detail in a Qualcomm document [2]—what follows is just a short recap:

An applicationm once startedm is in the active (running) state—capable of receiving all events, including key events (the active application owns the display). At any time, the application can be interrupted and be put in suspended state. A suspended application can become active again (resume).

Background applications are different; they have no way to interact directly with the user but they are in a running state. This makes them extremely attractive to be used as global services processing data in the background.

An application can be in the background for a limited period of time too—when receiving an event from another application. Global data repositories can use this feature to avoid some of the inherent limitations of background applications, which are otherwise notable. Other than not being accessible directly by the user, [2] mentions: " ... handsets running background applications will experience increased power drain due to the inability to enter standby mode; consequently, prolonged background execution should be avoided for its deleterious effects on handset battery lifetime. Some OEMs may limit the capabilities available to a background application; for instance, while running in the background, applications may be unable to open sockets or play ringers."

Exchanging Information

INotifier is an interface that might be used for initiating communication between two or more applications. Because INotifier will be discussed in more detail in a future article, we will concentrate our presentation on what IShell provides.

We can roughly qualify all the IShell calls of type

ISHELL_X(AEECLSID ....)

as inter-application communication. Once you know the clsid of another applet you can start exchanging information—;almost. Let's analyze for a moment the most useful methods (please note that some of these methods were enhanced—carefully read the documentation for the most suitable version and availability).

ISHELL_StartApplet() allows you to asynchronously start a different process from inside another process. The running process receives the EVT_APP_SUSPEND event immediately before the new application is started.

ISHELL_PostEvent() posts an asynchronous event to a specific applet, ISHELL_SendEvent being its synchronous counterpart. Because BREW is an event-based system, sending and posting events should be seen like the main vehicle for inter-application communication.

But, now comes the problem: An event cannot accommodate too much additional data to be passed through. Some developers might use the last parameter (an unsigned long) to pass a raw pointer from a process A to process B:

char* address = (char*)MALLOC(100);
ISHELL_PostEvent(shell, clsIdB, EVT_USER, command , address);

Unfortunately, this technique exhibits all the dangers presented before: "address" lives in A's context. Once A is destroyed, "address" is no longer valid.

What we need is a clean way to marshal data from process A to be consumed in process B. One way is to use a file in the SHARED directory as a pipe. PostEvent is simply used to signal the availability of data (it can describe meantime the size of the data chunk). For example, we might have in process A:

writeData2Pipe(&size);
ISHELL_PostEvent(shell, clsIdB, EVT_USER, command , size);
Process B consumes data in:
boolean CPPApp::OnEvent(AEEEvent eCode, uint16 wParam, uint32 dwParam)
{
   switch (eCode)
   {
      case EVT_USER:
         switch(wParam)
         {
         case command:
            readFromPipe(dwParam );    //dwParam is the size of data
            return true;
         ... ....
         }
... ..
   }
}

Of course, a more comprehensive protocol might be used, but this is the general idea.

Furthermore, A and B don't access the protocol directly, but via an extension hide all the implementation details.





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel