Design Article

IMG1

Mobile apps should be developed with platform independence

Leo Modica, Clarity Communication Systems Inc.

3/2/2006 3:39 PM EST

Collectively, manufacturers market hundreds of models of mobile devices, presenting today's consumer with innumerable choices. While this may be great for the consumer, it presents a seemingly insurmountable problem for mobile application developers.

Because of the disparities among platform operating systems (OSs)and application run-time environments, and the variety of form factors, companies must determine which platform to support. Making the right selection is the key to minimizing risks when the application goes to market. Unfortunately, predicting mainstream technologies six to nine months in advance is difficult as the industry undergoes dramatic technological changes each year.

Developing applications for a single platform often doesn't leverage a company's capital investment. Aligning with a single carrier or channel partner adds to the overall risk. If the partnership fails, companies have to quickly port their applications to a new platform and begin the difficult process of developing new partnerships. Should a company decide to develop an application for multiple platforms, the cost of implementing the application for each platform can be excessive. Most would agree that obtaining expertise in platforms is a painstaking endeavor. The only reasonable way to mitigate these risks is to develop an approach that enables developers to implement mobile applications in a platform agnostic manner.

Competing platform OSs
The key challenge in developing middleware for mobile devices is the degrees of variability inherent in platform OSs and application run-time environments. Each platform provides access to essentially the same underlying hardware devices and facilities, but does so using different APIs. Some APIs provide high-level access while others provide a lower level. Also, some APIs are more feature rich providing wider interfaces, while others are feature poor providing narrower interfaces.

Platforms vary greatly in terms of execution models (see the table). Some platforms are single-threaded and provide absolute control to the application developer while others are multi-threaded and provide non-deterministic behavior and a lack of control. Some platforms are completely asynchronous where APIs provide results using callback functions. Other platforms are completely synchronous and force the calling function to block until the results are obtained. These factors taken together provide the greatest challenge to middleware developers.


Proposed middleware layer
How does the middleware developer distill a common API that can adapt to a wide range of platforms? Abstraction is a powerful technique for generalizing differences among platforms. Design-pattern advocates view architectural layers as a key strategy for implementing abstractions. Introducing a middleware layer lets application developers develop to a common API regardless of the underlying platform (Fig. 1). Essentially, the middleware layer separates system invariants (applications) from system variants (platforms).


1. Adding a middleware layer lets developers employ a common API regardless of the underlying platform.

The proposed middleware layer is comprised of two categories of object-oriented classes: the Task Management classes and assorted Platform Adaptor classes. The Task Manager provides a common execution run-time environment that supports an asynchronous, event-driven execution model. These facilities enable real-time applications to execute with the same run-time semantics regardless of the underlying platform.

The platform adaptor classes provide a common API to all the platform specific resources and hardware devices. These APIs include classes that allow developers to interface to the display and keypad to create rich user interfaces with a common look and feel across platforms.

Multitasking environment
When it comes to run-time environments, each platform provides a very different execution model. All platforms, with the exception of Brew, support multi-threading. Each multi-threading model, along with their respective thread synchronization mechanisms, is fundamentally different in terms of functionality and language specific features. For example, J2ME uses JAVA-styled synchronizers while Windows Mobile uses a UNIX-styled locking and signaling mechanism. The Task Manager must abstract the application developer from these disparate, low-level threading mechanisms and provide an easy-to-use Task Manager that will enable quick application development.

Perhaps the most fundamental problem with these threading models is that they don't provide a common framework for multi-tasking. Most mobile applications are non-trivial and real-time. As such, they require a rich environment for specifying tasks that can communicate asynchronously using events. A common multi-tasking framework can be implemented on either a single- or multi-threaded platform. On multi-threaded platforms, multitasking allows events to be processed in parallel and can therefore provide better real-time responsiveness to high priority events.

The Active Object design pattern has been used successfully to develop middleware systems such as the ACE, Rose RT, Symbian , and numerous other. Effectively, Active Objects implement tasks and provide the basic framework for multitasking. Each Active Object executes on a separate control thread (Fig. 2). On single-threaded platforms, the Active Object shares the common application thread. Active Objects are event driven. Events are sent to Active Objects from other Active Objects, the user interface, or callback services. Events are queued for the Active Object in a message queue. The Task Manager is an Active Object based system that serves as a mini-kernel. The Task Manager synchronizes the queuing and de-queuing of events as well as the scheduling of Active Objects to service events. Active Objects process events using run-to-completion semantics.


2. Active Objects implement tasks and provide a basic multitasking framework.

The benefits of Active Objects are:

  • Active Objects decouple method invocation from execution using event queues and prioritization. This provides better real-time response to time-critical events.
  • Synchronized event queues provide thread-safe communication between Active Objects and external events.
  • Active Object member methods and data are bound to a single control thread. This ensures that an Active Object's members are only accessed by the object's dedicated thread, alleviating the need for synchronization mechanisms to protect member data.

The Task Manager is implemented using the Active Object model. Classes for implementing the Active Object task and event are provided. Additional classes are provided to implement services such as application construction/destruction and application global data. Compared to Rose RT, ACE, and other Active Object implementation, the Task Manager is lightweight and well suited for low-tier mobile devices.

To implement a task in the Task Manager, the app developer inherits from the Task class and overloads the run method. The developer implements additional event types by extending the Task Manager's Event type enumeration. The Event class is implemented using the Command design pattern. It provides methods for sending, replying to, and canceling events. A timeout feature returns an Event to its sender if the Event isn't processed in a specified time period.

Platform adaptors
Two key challenges in developing adaptable apps are the difference in platform APIs and the synchronicity models used by each platform for accessing system resources and devices. Platform APIs differ in terms of breadth and depth. In terms of breadth, some APIs are feature rich (wide) and others are feature poor (narrow). In terms of depth, some APIs provide high-level functions while others provide low-level functions. Developing an adaptor with a common API for a specific interface requires the middleware developer to balance the aspects of breadth and depth.

Synchronicity refers to the manner in which the platform provides the response to a resource/device request. Some platform APIs are synchronous. They require the Active Object to block until the request can be completed. Typically, responses using synchronous APIs are provided as return values using the call stack. In general, synchronous APIs aren't well suited for event-driven, real-time systems.

Other platform APIs are asynchronous. They require the Active Object to register for callbacks before the service is requested. When the request is completed, the platform passes the return values to the Active Object by calling the registered callback method. The callback is typically made on a platform-provided thread. On some platforms, ready events are passed to the Active Object, requiring the object to read the values from a buffer or device. Adaptors are developed using abstraction. Through abstraction, the middleware developer generalizes the full range of platform-specific APIs for each resource/device into common, platform independent API that expose the essential functions. Non-essential functions aren't exposed. The Adaptor design pattern helps develop common APIs to platform-specific resources/devices. Using the object form of the Adaptor pattern, the Adaptor accesses the platform-specific API by encapsulating an instance of or reference to the platform-specific API.

Guidelines for developing effective abstractions are:

  • Implement the adaptor as a wide API and nullify the features that aren't available in the subset of the platforms not supporting them. Applications can test the common API to determine if the features are available.
  • Implement the adaptor as a high-level API and hide low-level functions behind the high-level interface. This approach will facilitate rapid application development. Implement the adaptor to provide a complete service. For example, a file adaptor should allow the application developer to create, delete, test, and modify files. Make sure the services exposed by the adaptor can be implemented in a semantically consistent manner behind the API for all platform-specific APIs.

To be faithful to the Task Manager's event-driven, real-time nature, adaptor methods shouldn't block for an indeterminate amount of time. For transaction-styled platform APIs, adaptors can be implemented as simple call-throughs where the platform-specific API renders the complete service in the single method call without blocking. These are known as synchronous adaptors. In cases where the platform-specific APIs can't render a service in one method call, asynchronous adaptors are needed.

Two types of asynchronous adaptors are defined: stateless and stateful. Stateless asynchronous adaptors are implemented as a conduit for callbacks. The adaptor simply registers for callback with the platform-specific API. When the callback occurs, the adaptor passes the return values to the Active Object as an event through the Active Object's event queue. The Active Object receives the event as it does any other asynchronous event.

Stateful asynchronous adaptors are implemented as finite-state machines (FSM). Such adaptors are required when the platform-specific APIs themselves are stateful. For example, HTTP adaptors are stateful. The HTTP adaptor must be implemented as an FSM to handle all failure events, guard timers, extended write and read cycles, and perhaps a retry strategy. Stateful adaptors should be implemented as Active Objects.

Platform adaptors with a common API are implemented for the following typical mobile resources and devices:

  • Backlight
  • Camera
  • Database
  • Display
  • File system
  • GPS
  • Keypad
  • Microphone
  • Pen/stylus
  • Phonebook
  • Protocols (HTTP, HTTPS, TCP, UDP, TCP/SSL)
  • Sound (tones, audio, MIDI)
  • Speaker
  • Time (UTC)
  • Transports (GPRS, 1xRT, EVDO, 802.11, Bluetooth)
  • Video
  • Vibrate
  • Vocoder
  • Voice (basic speech recognition)

Developing the common UI
Perhaps the most complex aspect of developing the proposed middleware layer is the user interface (UI). These complexities arise primarily because of the plethora of form factors. Some mobile devices have large screens with touch pads and full keyboards, while others have small screens with keypad entry only. Some devices support soft keys while others have dedicated keys.

The primary goal of developing a common UI is to provide the end-user with a consistent interface across devices. A secondary goal is to be able to develop a UI that can be targeted to multiple devices while being true to the specific device UI conventions. To achieve these goals, a common set of display and data-entry conventions must be adopted. These conventions are governed by the common capabilities of mobile devices. Most mobile devices sold today have color displays with pixel graphics, keypads with numeric/alpha keys, and keys for selection and back/cancel functions (either dedicated or soft keys).

Stateless asynchronous adaptors are used to implement common UI services within the middleware layer. These adaptors support both widget- and graphics-based displays (Fig. 3).



3. Stateless asynchronous adaptors can implement common UI services within the middleware layer. These adaptors support both widget-based displays (upper figure) and graphics-based displays (lower figure).

A partial list of conventions used by the middleware layer are:

  • Soft keys are used universally for selection and cancel/back functions.
  • Soft-key functions are activated using the touch pad, soft keys, or the dedicated OK/Back keys. For devices with such keys, the OK key maps to the affirmative soft-key function (e.g., Select, Menu) and the Back keys map to the negative function (e.g., Back, Cancel, Exit).
  • Additional soft buttons are used on devices with larger displays. These buttons are supplementary and map to functions already provided on pop-up menus. The soft buttons are only rendered on devices with touch-pad capabilities.

Usability and extensibility
For middleware to be adopted by a wide range of apps developers, consideration must be given to its usability and extensibility. Usability refers to the manner in which the developer uses the middleware layer to build a mobile application. Extensibility refers to way in which the developer customizes the middleware layer to meet specific application requirements. Usability and extensibility are facilitated using the framework architecture pattern.

A framework is an integrated collection of components that collaborate to produce a reusable architecture for a family of related applications. In the case of the Task Manager, the Task and Event classes work together to provide a complete multi-tasking service. These classes provide an inversion of control common among frameworks. The Task Manager is in control of the application at all times. As Tasks are scheduled, the Task Manager executes Tasks by calling their run methods. In so doing, the Task Manager delegates control to the application.

Frameworks are designed to be customized and extended by the application developer. Middleware design decisions that may be of interest to the application developer are deferred until application development time. Application developers then customize and extend frameworks using the following techniques:

  • Class derivation is used to specialize framework base class data.
  • Method overloading along with class derivation overrides methods provided by framework base classes. Control is provided to derived class methods using virtual method constructs.
  • Data customization initializes framework parameters.
  • Registration and callbacks gain control from the framework when conditions for which the application is registered arise. Control is provided to registered classes using virtual constructs.
  • Type extensions extend framework types (e.g., enumerations) and allow the framework to recognize application types.

The proposed middleware layer is implemented as a framework. Class derivation and method overloading are used by the application developer to derive Active Objects from the Task class. Event type enumerations are extended to implement application specific event types. Data customization, class derivation, and method overloading customize the look and feel of the UI display classes.

Choosing a programming language
Application portability across platforms is determined by the choice of implementation language. Fortunately, Java and C++ are supported on most of today's devices and offer good performance for most real-time apps. Thanks to Moore's Law, performance continually improves with each new crop of devices.

In certain situations, C++ may be the best choice. If C++ is chosen, the developer must determine if any coding restrictions are imposed on them by the compiler vendor and/or target platforms. For example, on Brew platforms, the application developer can't implement global data and exceptions. Application developers should evaluate each compiler and platform before choosing C++ as the implementation language.

To promote complete portability across all platforms, the miJava programming language has been developed. miJava is a platform independent subset of J2ME. Essentially, it's Java plus the container classes found in J2ME. These container classes include Object, Vector, Hashtable, String, StringBuffer, Byte, Short, Integer, Long, and Boolean. Mobile applications implemented in miJava can be deployed on all J2ME supported platforms and all C++ platforms. A special compiler translates miJava into C++ that's compatible with all platforms. All the J2ME container classes have been implemented in C++ using the Handle/Body idiom to support miJava applications running on C++ platforms.

About the author
Leo Modica is a principal software engineer at Clarity Communication Systems. He can be reached at lmodica@claritycsi.com.


print

email

rss

Bookmark and Share

Joinpost comment




Please sign in to post comment

Navigate to related information

Product Parts Search

Enter part number or keyword
PartsSearch

FeedbackForm