Login | Register
My pages Projects Community openCollabNet

Introduction

Lightblue BREW C++ wrapper library (abbreviated  as lbcw) is an efficient C++ binding of Qualcomm's BREW SDK which is widely used for developing  mobile applications and games for CDMA mobile platforms.  QUALCOMM’s Binary Runtime Environment for Wireless® (BREW®) follows an object-oriented design, which exposes its functionality through BREW Interfaces. However, by some reason, BREW Interfaces are declared as C structures instead of C++ classes. This makes them hard to use and extend.  Nowadays, the mobile platform becomes more powerful and  makes the creation of  feature-rich applications possible.  When the application goes bigger and more complicated, the C API  shows its limit.

The lbcw library make the developing of complex BREW applications and extentions much easier by declaring all BREW interfaces into equivalent C++ abstract classes without any speed slow down or executable size increase.  All BREW Interfaces are used exactly as C++ objects.

The creation of BREW Extensions has never been easier; you can now create your extension interfaces that are directly inherited from any existing BREW Interfaces  using the C++ inheritence.

Since version 0.8.6, a copy of pre-generated header files are included in the lightblue distribution which contains the C++ class declaration of all BREW interfaces from BREW SDK 2.1.3 and 3.1.4. Any new SDKs will be supported when they are released by Qualcomm.

Highlights

  • Ease of  use. BREW Interfaces are now C++ Classes. Use or extend (inherit) them as you do to C++ classes.
  • Extreme fast. There is absolute NO EXTRA COST of  calling a brew interface using the C++ syntax.  For example  pIShell->Beep()  and ISHELL_BEEP(pIShell) generates identical assember code. Sometimes, it is even faster than the C implementation by reducing unnecessary function call overheads. For example, the HandleEvent() method of the IBrewApplet eliminates one level of function call than the orignal implementation. Considering the high frequency this method is being called, usally  30 to  40  CPU  circles  are  saved  per  second  for an application updates itself  frequently.
  • Compact  executable size.  For C++ programs that need relocation, only a 140 bytes startup code is added to the beginning of the mod file which relocate the function pointers and calls the constructor of each global C++ objects before the entry point of the MOD is called.  However, since the Realview 2.x compiler is supported, the generated assembler code to call  virtual functions reduced from 4 instruction to 3 instructions, which result in smaller and faster code. 

Features

Below is a  list of features that the lbwc library are current providing:

Accessing  BREW Interfaces as C++ abstract classes

BREW Interfaces are C++ classes now.  Their methods could be accessed using the "." or "->"operator from the Interface instance.

Creating  BREW Extensions by C++  inheritence

If you want to create a BREW Extension that  exposes  interfaces extended from existing BREW Interfaces to other applications, you just create a C++ class that inherited from that Interface. No complicated macros and manual object memory initialization is needed. All using the builtin C++ object creation machenisms.

BREW Interfaces and  C++  classes are interchangeable


Every functions that accepts a specific  BREW Interface will also accept the equivalent C++ wrapper class. For example, the IDISPLAY_SetFont() method accepts an IFont interface as its last parameter and the IFont interface's equivalent C++ wrapper class is IBrewFont, you can write following code:

IDISPLAY_SetFont(pthis, (IFont*)MyFont); //MyFont is actually an instance of  IBrewFont.

Better compile time type checking and polymorphism

By reading the SDK document, we know that IUnzipAStream inherits from IAStream. However, all this are logical, the compiler don't know this, we have to explicitely cast an IUnzipAStream pointer to an IAStream pointer to get it accept by a function that accept IAStream pointer.

 When using the C++ wrapper classes, IBrewUnzipAStream class  is inherited form IBrewAStream. So  every  functions  that  accepts  an IAStream pointer will accept a pointer to an instance of IUnzipAStream. By this facility, explicity type casting is not as frequently used as it  is in the C program.

Static and  global variable supported

This major issue  annoying the  ADS  compiler  users  has  been  solved.  Static and global variables are now supported without any limitations. Global objects are also supported whose constructor will be called before the entry point of the mod is called.

Notes: This feature is actually provided by the lightblue post linker(lbmg.exe)

Structure of the library


The lbcw library contains two parts: the runtime and  the BREW Interfaces wrappers which is generated automatically by the lightblue header generated(lbhg.exe).

The runtime part contains a single cpp file called "entryptr.cpp" which is a replacement of  AEEModGen.c and AEEAppGen.c.  The "entryptr.cpp" only contains less than 150 lines of code but does the same job as  AEEModGen.c and AEEAppGen.c that have 800+ lines of source code in total.  The result object file size  remains  no  differences or smaller.

The BREW Interfaces wrappers are automatically generated.  They are declared in "hpp" files that  have the same base name as the "h" files in the original BREW SDK. Two set of  wrapper classes are included in the lightblue distribution package:

include\213\ *.hpp             --Wrapper classes for BREW SDK 2.1.3
include\314\*.hpp              --Wrapper classes for BREW SDK 3.1.4

Notes: When using these wrapper classes, the orginal BREW SDK is also needed.

Why the wrapper classes works

The wrapper classes do not contain or reference the BREW Interface it wraps, but why it works?

The C++ compiler will create a hidden table which is often called v-table ( virtual function table) for every class that has at least one virtual function.  When a vritual function is called, the actual address of it is retrieved from the v-table at execution time. That's why calling virtual functions is slower than calling non-virtual functions whose address are known at compile time.  For most modern C++ compilers, the v-table is implemented as an array of absolute address to the virtual functions.  For every instance of the class that contains virtual functions, the  first  4  bytes  holds  the  address  to  its  v-table.

For example, if Class "CClass"  has a virtual function called  "draw()" and "pClass" is a pointer to an instance of CClass, when we call pClass->draw(), the compiler will generate assembly code like following pseudo c code:

void ** v-table = (void**) *((int *)pClass);
void*  address_of_draw =v-table[1]; // assume that draw() is the second virtual function of CClass;
address_of_draw(pClass);

Let's go back to the implementation of the BREW Interfaces.  The method of  BREW Interfaces can be called by macros that usually has the following pattern: <CLASS_NAME>_<MethodName>(pthis, ...);  For  example,   if  you  want to call the Release() method of  IGraphics, you type: IGRAPHICS_Release(pIGraphics); the IGRAPHICS_Release() macro is expend to

GET_PVTBL(p, IGraphics)->Release(p));

which in turn expends to:

 ((IGraphics*)p)->pvt ->Release(p);

pvt is the first field of IGraphics and  is a 32bit pointer.  If we debug the code in assembly level, we can find that it generates  identical assembly code as a C++ virtual functions is called.
Now let's  seperate the above code in three lines of equivalent code:

vtable* v-table =  ((IGraphics*)p)->pvt;              // same assember code as void ** v-table = (void**) *((int *)pClass);
pRelaseType*  pRelease = v-table->Release;     // same assember code as void*  address_of_draw =v-table[1];
pRelease(p);                                                      //same assember code as address_of_draw(pClass);


So if we declare a C++ class that contains identical methods as a BREW Interface and declare these methods as the same order as they are declared in the BREW Interface,  the v-table of the C++ class will  identical to the BREW Interface.  We can thus use this C++ class as a wrapper class of the BREW Interface.


Compiler supported

  • GNU ARM compiler. You can get a pre-compiled GNU ARM compiler from gnude website. 
  • Realview ARM Compiler 2.x from ARM.
  • Visual C++ Compiler. (For the simulator build)
More compilers will be supported in the future versions.

BREW SDK supported

BREW SDK 2.1.3 and 3.1.4 are supported.