Wednesday, July 25, 2007

Porting 101 or How to destroy an industry...

One of the mobile market's major problems is the porting issue. Everyone in the industry is aware of the grim fact that every mobile application you make, you have to port to hundreds of mobile phones. The porting efforts can sometimes exceed the R&D time for the entire application... This issue holds the whole industry back, and must be resolved to get the mobile industry to the next phase.

I wanted to write about this subject for a long time, but it is so elaborate that every time I tried to, more and more issues popped into my mind... So I decided to "just write it", knowing that I may have missed a few things, but I would like to dig a bit deeper into the roots of the problems, as the effects of it are already known...

Unlike PCs, mobile phones are very different from one another. It begins with a different hardware (screen, memory, multimedia capabilities) and ends with a different OS/Virtual Machine.

One of the major differences between phone is what OS/VM they support. Some support Sun's Java (J2ME), others Qualcomm's Brew, others support Symbian and then there's the Windows CE smartphones and the Linux-based phones etc.

Going from one of the platforms listed above to the others, is more than porting - it is actually rewriting the application (And managing several codebases afterwards), and if all of the above would have had equal market shares - we might have been in a bigger problem than we already are... However, Luckily for us there is one platform that stands out, and that's J2ME.

Sun's J2ME (aka JavaME) is the dominant platform, especially in Europe, and even in the US it is becoming the de-facto standard pushing Qualcomm's Brew aside. J2ME is a Virtual Machine and as such is sometimes supported on top of other OSs, and that's what makes it so popular.

The problem is that even within J2ME, you still have to write slightly differently for various devices. Do you know Java's Motto "Write once, run everywhere"? Well in J2ME it's more like "Write once, port to 10 zillion devices, test till your fingers hurt and then hope for the best"...

Why does it have to be like that? Well, here are some of the major reasons:

1. Different profiles - Sun has defined two profiles for J2ME based mobile phones. The older one is called MIDP 1.0 and has limited features in terms of graphics manipulation, UI widgets, communications etc. The newer one is called MIDP 2.0 and is much more advanced and contains a more natural support in gaming needs. Today all devices going out to the market support MIDP 2.0, but there are still many MIDP 1.0 devices out there (For example Nokia Series 40 phones such as 6100,3100 are MIDP 1.0). In any case due to the limitations of MIDP 1.0 more and more content makers are not supporting it anymore.

2. DIfferent APIs - Some standard J2ME APIs are not necessarily available in every device. For example in the MIDP 1.0 days, the multimedia API (MMAPI) was not a "must" to define a device as MIDP 1.0 compliant. In the same way, today MIDP 2.0 contains a set of APIs the device must support, but many of the newer APIs, such as Bluetooth, PIM (Contact list access) and more are not a "must". Now, bear in mind that you can't just write a code that checks if that API is available and only if it is use it. If the API is referenced from your code and it is not available - your application will simply not run at all! So again you have to provide several codebases.

3. Proprietary APIs - In addition to Sun's formal specs and APIs, mobile devices vendors add to their phones special proprietary APIs. Usually these APIs allow the developer to utilize new technologies, or just supply a more native interface to the device hardware. The problem is that sometimes in order to create an application/game you have to use these APIs since if you don't everything would run very slow. A good example for that is NokiaUI which was an API that allows an accelerated graphics performance and enables some MIDP 2.0-like graphics manipulations in MIDP 1.0 devices.

4. Buggy Implementations - It is not uncommon to find standard J2ME versions that simply do not implement certain methods, or implement them in a wrong way. Sometimes the vendors are aware of this and mention it in their API documentations, and sometimes the developers themselves find it. So it is possible that two devices that implement the same profile, same standard APIs and same proprietary APIs, would still not work the same. For example, in Nokia 6680 if you'll try to rotate a sprite it will cost you dearly in the heap space (memory) of the device, and most likely crash it altogether...

5. Different hardware - Even if two devices share the same profile, APIs and implementation, their hardware attributes may affect how the code and even the graphical assets should look like. For example if one device has a resolution of 128x128 and the other has 240x320, you may have to produce different graphical objects for each of those. Also you may find yourself changing the UI concept altogether in the 128x128 device as it is too small for a UI that is best seen on 240x320.

The good news is that Sun is working closely with vendors to make a compliant set of APIs that should be more definitive (read my post on the MSA standard). The bad news is that we have heard before of other standards that didn't catch on in the market (Such as the JTWI). The problem is that even if one vendor does not adhere to the standard - all hell breaks loose.... (Not to mention the legacy devices that will affect us for 3 years regardless).

So let's wish Sun some luck, the mobile industry needs it...

P.S. - The photo above was taken in GamearraY's offices... These are just some of the handsets we have... So it's cool to get the newest gadgets all the time, but every such "gadget" comes with the intent of giving our developers a hard time in the porting process...

10 comments:

Unknown said...

Hi Ofir, my name is Luca Passani and you probably know me because of my project (WURFL) which you also mentioned in another post of yours.

Thank you for the nice summary of J2ME challenges. Your article was discussed by members of the new WURFL-J2ME list and everyone substantially agreed that you got it all (some had more J2Me issues to mention).

Anyway, I just wanted to let you and your readers know that knowledgeable J2ME developers have gathered around a new MODERATED mailing list:
http://tech.groups.yahoo.com/group/wurflj2me/

The point of the list is to agree on a mapping of J2ME issues that can be described programmatically in WURFL. At that point, all the information that each company has collected about phones in their domain would be shared in order to help one another and the J2ME developer community in general.

J2ME newbies are accepted on the list as long as they keep a low profile (once more, the list is moderated, so SPAM and stupid questions will cause the originator to be ejected without even delivering his/her message to the list).

Thank you

Luca Passani

Anonymous said...

Hi,

Nice summary, but one thing is not correct: "Now, bear in mind that you can't just write a code that checks if that API is available and only if it is use it. If the API is referenced from your code and it is not available - your application will simply not run at all!".

I had the same problem and I found out a solution for this. If you would like to hear it send me a mail and I'll send you an example!;-) My e-mail address: h.gergo@freemail.hu
Cheers,
Gergo

Ofir Leitner said...

Hi Gergo,

I really don't see how this is possible.

For example if you would like to use the multimedia API (MMA) which is not available at some old MIDP 1.0 devices, then you would have to import the MMA package in your code, and use the various classes there.

If you try to compile such a code in that device's emulator, you would get a compilation error.

And if you try to compile it using a device profile that has MMA and then download to the device you would get an error on the device itself (Probably invlaid application or something like that).

I really don't see how anyone can circuvent this without porting.

Ofir.

Torben Vesterager said...

Yeah, there are many ways of detecting APIs and the manufacturer implemented support for those APIs:

* Check for a unique API class:

private static boolean isMMAPIAvailable() {
try {
Class.forName("javax.microedition.media.control.VideoControl");
return true;
} catch (Exception e) {
return false;
}
}

After that you can instantiate a class which imports MMAPI classes.

* Check manufacturer implementation quality:

System.getProperty("supports.audio.capture")System.getProperty("supports.video.capture")System.getProperty("supports.recording")
etc.

Anonymous said...

I assume that Gergo is talking about the fact that you can always use ClassLoader to find out if a particular java package is available. Using this and some form of factory should provide a fairly seamless solution where you can attempt to create an object of a certain type and find out at runtime if it isn't possible.

Ofir Leitner said...

Yes, you are all correct... Using the classloader is now becoming more and more common. I even saw this at Sun's new UI API (LWUIT), they use it to detect whether JSR-184 (3D) is supported and if so - use it.

Of course it makes the coding less pleasant, but what won't we do for a better porting process...

Anyway, back in the early days, you couldn't even rely on the VM (Hence the classloader) to be bug free, so using this same technique could still cause problem.

But today, Mobile VMs have become more stable. Usually the core part including the classloader can be relied upon, while most bugs/implementation differences are found in higher level APIs - thus making the classloader approach safe to use in most devices.

Another reason this method was not widely used before is the code overhead it produces - from a JAR size perspective it is better to have preprocessing that either includes or omits all uses of the API in question.

But today the porting issue is much bigger than the JAR size which is becoming less of a problem in most devices - better have a bigger code but same for all devices, than having to go through a painful porting process.

In any case I believe that using this approach is application specific - i.e. in some you would prefer it, in others, you would prefer to save code, especially if you have an API that you make a very heavy use of, and it simply makes no sense packing it in weaker devices to save porting (And this gets worse if you have 5-10 such APIs).

So, go on a case by case basis.

Adam Kecskes said...

My company currently ports both for BREW and J2ME. We find J2ME is easier to create the apps, but hard to port. What challenges us most in our own porting efforts are the lack of file space access (JSR-75 isn't widely available and may not even do the trick) and the need to sign the app in order to access certain APIs. To add to your 'different hardware' point, low-memory issues are also a huge problem, and there are a lot of low-memory J2ME phones out there (at least relative to our application).

Anonymous said...

use this

try {
Class.forName("javax.microedition.media.control.VideoControl");
return true;
} catch (Exception e) {
return false;
}

in a thread or else some midp1.0 phones crash because they cannot find the class

Tom Godber said...

Nice summary, I think there were a few things missing but as you say it's a complicated area! I did a similar post a while back with a few extra things thrown in: http://blog.masabi.com/2008/01/truth-about-mobile-fragmentation.html

On the Class.forName issue - we used to use this technique many years back but found it failed on some JVMs, I think it was JBed which precompiles the code on installation rather than using runtime bytecode interpretation, so it always found the missing API calls and refused to install. There were some other issues maybe with Sharps and certain packages as well but I'm afraid it's all some time in the past.

To really handle the UI variations required with different screen sizes, APIs and input paradigms (touchscreen, QWERTY, numeric keypad etc) you have to go with lots of build variations targeted at build time though - easy to do once you're set up for it but takes a bit of time to learn...

Anonymous said...

Hi,

You can find a demo application and a description of my solution on the following link:
http://mobile.motoros.hu/j2mefaq
if you want to comment my solution send me a mail.
Cheers,
Gergo