Compiling native apps for Android explained

In my daily work (the one that pays the bills) I've been burdened with the responsability to port two projects to the Android platform: hop, a programming language for the web 2.0/application server writen in Scheme. For that I would need to also port bigloo, a Scheme compiler. The goal is to be able to run hop apps in the phone itself.

I really didn't know much about the platform then, only that probably it would be a fun platform to have in your phone, being GNU/Linux based, open source and all. There was also the promise to play with these phones; being somewhat a technophile, that was definetely a plus. With a smile in my face, I cracked may hands, sat down and started... reading.

The first thing one learns when reading about developing for the platform is that the language is Java. There's a complete SDK for developing them. If you want to port some C/C++ library, you can do so with the NDK, and that's pretty much it. Now, from my point of view, this is very restricting: you cannot choose your own programming language. Even if I like the language a bit (but not its std library or the way that the language is driven), I prefer Python or whatever suits better the problem. But then, I understand Android/Google/OHA needs to be control freaks with the apps running on the phone, because there are limited resources and you cannot leave an application open forever. So, they devised their component lifecycle, which reminds me of OSGi, made it in Java, made all the tools and that was it.

But in my case I needed a native port, and that's for two reasons. First, even if bigloo can produce Java bytecode, and even when I've been told that Dalvik, their JVM implementation, can run Java bytecode1, the result is not fast enough, being a both bigloo and the JVM in turn problem. Certainly bigloo's Java output might not be the best, but also the JVMs we tried were too heavy2. The second and most important reason is that if we did a Java port, we would be tied to the component lifecycle I mentioned above. We need a hop daemon running in order to be able to run its apps. If this deamon goes off by the platform's request3, there's no way to awake it again when a (web) client tries to make a request4, so the request would fail and would make hop useless. Hence, a native port5.

I have to say in everybody's defense that this is my first contact with toolchains and cross compiling.

Given that native porting is not supported, I went off searching. The first posts talked about static linking. This guy even pointed to a first wrapper for the precompiled toolchain and gave some details on some CFLAGS to set. But static linking was not an option for us. hop uses bigloo's runtime libs as dynlibs6.

Then I hit Rob Savoye's efforts to port gnash. There I started to fully understand the Android platform: «while the C compiler is ok, the C++ compiler is crippled. No iostream support in libstdc++, no locales, etc... Then to make it more fun they use their own libc called Bionic, which is trimmed down for embedded devices». He has more details on C++ compilation because he needed it (we don't... yet).

So I turned to what I knew, if it only was its name: emdebian. I was till a litle hazy about what cross compiling meant, so I started to make questions. Thing is, emdebian is coupled with Debian (it only makes sense), so the first step would have been creating a Bionic package. Of course, this was way beyond my requirements and abilities. In that channel I was also pointed to a post by Harald Welte, which in turn links to a talk called "Android Mythbusters", where we learn also that the linking is not standard [s.6], some hacks in the device support [s.7], hardcoded hotplug [s.8], no tslib support [s.12], hardcoded limits [s.13], and a lot more of calamities, including bad community support [s.18], and its peak, the CyanogenMod-gate.

All that analisys is nice, but I was still stuck with no porting system. My boss suggested scratchbox, but just like emdebian it only has support for (e)glibc and uClibc. It is possible to add support for other platforms, but their script didn't work and my feeble attempts led me no closer to a solution.

Then with a strike of luck I found Joel Reymont's Android Notes, who not only explains a little more the platform, but also has a example Makefile for compiling executables for Android. And then, just a few minutes later, Takuya Murakami's wrapper, which, together with the prebuilt toolchain in Android's source code, made most of it. I finally got a simple Hello World! dynamic executable running in the emulator.

From here all was mostly downhill. The last stone in the path was a linking problem. bigloo uses Boehm's gc, a renowed garbage collector used by several proyects, including mono and ocalm. gc needs a symbol called __stack_base__ defined, which, from what I could find looking, used to be defined in crt0.o, one of the parts that the compiler normally attaches to executables to make them so. The problem is that this file is not in the SDK or Android's source code/prebuilt toolchain. To be fair, that file is not to be found in a fairly new distro. What I found was a reverse engineered crt0.S 7, but it doesn't define the symbol I needed, and in any case I already got running executables in the emulator. In the other hand, naoya_t seems to have hit the same problem, but he writes in japanese and I couldn't get hold of anyone to translate it for me8.

Long story short, I made a hack to make the linking happy. bigloo finished compiling, I pushed it to the emulator and... it worked!

Some notes about this port: with a little bit of luck it will be officially announced next week, even if it works with a hack. Ivan Maidanski assures me that it should not be nessesary, so probably there's an error on our side when configuring gc; but then again, I spent more that 2 weeks with that problem alone and I followed all the suggestions they gave us9, so I'm pretty sure is something in the middle. Also, mono has been ported to Android, and even if I read references to the NDK, I've been assured that it's a native port. If they could port it without hacks, so should we10.

Lastly, some notes about the crippled GNU/Linux running behing the Android platform: besides all the low level stuff mentioned by others cited above, there are no cp or tee; ls does not support the -R option, mkdir does not support the -p option, and even when one of these tools don't recognize an option, instead of barking, it happily accepts it as another file to treat. so, mkdir -p bongs/bonga creates a -p dir and barfs on bongs/bonga. What it is there, yes, are dd and strace! Not very surprisingly, there's no /etc/passwd, but then the system somehow knows several others users besides root and shell, so I guess they're hardcoded somewhere. It's really impressive the effort they put to cripple this thing. Most probably they're using a tool like BusyBox11, and if so, they are only saving some directory entries in the case of cp or tee and wasting time in the other cases.

All in all, I'm dissapointed by the platform. I understand that what we're trying to do is not supported, and that alone tells me that I don't want an Android device until this has changed, if it ever does. Probably the fact that Android is (now) open source and that the Cyanogengate led to the formation of «the Open Android Alliance (not to be confused with the Open Handset Alliance) an organization whose stated goal is to distribute "a Flavor of Android that is fully customizable and does not rely on Google or other copyrights» gives the platform some hope.

Meanwile I will prefer Maemo (who at least looks more open), specially now that Qt will be the default toolkit. I'll also keep an eye on Bada, Samsung's new platform. There are not many details about this last one, except that they have their own toolkit in C++, and from the API's documentation, it looks like it's a very thorough one.


  1. but then the WikiPedia page says you have to convert the .class file in a .dex file using a tool called dx, and that «It uses its own bytecode, not Java bytecode». 

  2. but then Dalvik is supposed to be fast enough for the platform. 

  3. «If an activity is paused [not having the focus] or stopped [run at some time but obscured completely], the system can drop it from memory either by asking it to finish (calling its finish() method), or simply killing its process». 

  4. because instead of communicating via Android's component system, the communication is via a simple TCP socket. 

  5. but probably we'll have to make at least a Java wrapper to start it. I'm even pondering making a "hop apps" app which would be a WebKit widget and a hop server runnning in the background. 

  6. or in any case I would need to compile bigloo first dynamically to get the libs to compile hop staticly. 

  7. that blog has some more details about porting to Android. 

  8. a chineese friend could read some, but his translation didn't make more sense than google's. babelfish just timed out on that page. 

  9. the ones that made sense, anyways. 

  10. when I was looking for anyone involved in mono's irc channel, I was told to look in the code. A simple “noone involved is here, try reaching them by mail” would have sufficed. Way to go, mono community! 

  11. and if they're not, then I don't know what's going on in their heads.