This is the first article about porting Android 4.0.x AKA Ice Cream Sandwich AKA ICS on the OpenRD Client. This is a pretty powerful ARM machine (1.2 Ghz 256 KB L2 cache, 512 MB RAM and Gigabit Ethernet) with a PCIe Xgi graphics chip. The goal is having a good hacking machine, so the system will be brought up via NFS root (perhaps in a future part everything will be put on the internal NAND or a SD card, it should not be difficult).
The standard U-boot provided with the OpenRD is used to boot the system. The environment of the boot-loader has to be set-up to start mainline kernel, as outlined on the Debian on the OpenRD page. The Android kernel and users-pace will be loaded via the network (the IP and paths refer to my development environment):
setenv bootargs 'console=ttyS0,115200 root=/dev/nfs ip=10.0.10.187:10.0.10.57:10.0.10.57:255.255.255.0:openrd:eth0:off nfsroot=10.0.10.253:/mnt/fat/armroots/icsrd,tcp,nolock init=/init rw' tftpboot 0x00800000 openrd-android ; bootm 0x00800000
The Linux Kernel
After some research for a Linux kernel with appropriate Androidism I choose to start with the kernel published by Freescale on their Open Source git repository. I had good results with their kernel on i.MX28 and i.MX53 based machines. The patch for the OpenRD are based on the imx_2.6.38_android branch, tag imx-android-r12. ICS is based on Linux 3.0 kernel but I haven't seen big problems using this version (just some warning about missing some IP connection tracking statistics in the sysfs file-system). You can download my latest patch for supporting the OpenRD board and the .config file I used. This patch:
- adds support for the Xgi frame-buffer I took out from the Marvell provided tree. There is a similar driver in the staging drivers directory but it didn't work well and i preferred to stick with the driver I use normally on the OpenRD while hacking with Linux.
- the frame-buffer driver is fixed to not allow allocation of a double-buffering surface. I haven't dug in this problem yet, it looks like the Xgi driver reconfigures the graphic chip on every buffer flip creating a terrible flickering effect.
- a patch for a bug in the correct handling of the L2 cache (which, unfortunately, didn't get it's way to the mainline kernel) is applied.
- some other minor fixes to support Android specific OOM killer (Kirkwood arch doesn't have ZONE_DMA) are implemented.
By the way, the tool-chain used to compile the kernel is the standard Codesourcery one.
Android user-space compilation
It's quite an adventure to build Android ASOP from sources. I strongly encourage you, if you are, like me, new to the Android planet, to read the wonderful book Embedded Android by Karim Yaghmour. I bought it as a pre-release but I'm sure the the four initial chapters alone saved me lot of hours browsing the Internet. I started from the 4.0.3 tag in the ASOP repo. The first step is to setup the build environment. The build dependencies are rather complicated. Following the book mentioned above this is what was needed on Debian Squeeze:
aptitude install bison flex gperf git-core gnupg zip tofrodos build-essential g++-multilib libc6-dev libc6-dev-i386 ia32-libs mingw32 zlib1g-dev lib32z1-dev x11proto-core-dev libx11-dev lib32readline5-dev libgl1-mesa-dev lib32ncurses5-dev sudo ln -s /usr/lib32/libstdc++.so.6 /usr/lib32/libstdc++.so sudo ln -s /usr/lib32/libz.so.1 /usr/lib32/libz.so
Much more complicated is to get rid of the OpenJDK/gcj Java tools incompatible with Android. I didn't want to remove them because a whole lot of other packages depends on them. After installing latest Sun Java 6 SKD in /opt/java/ I sanitized the shell environment:
export PATH=/opt/java/bin/:$PATH export JAVA_HOME=/opt/java/ export java_home=/opt/java/ unset _java unset _java_classes unset _java_find_classpath unset _java_find_sourcepath unset _java_packages unset _java_path export ANDROID_JAVA_HOME=$JAVA_HOME
The next step is writing a configuration file for the board (under device/evol/openrd for example). Much of this is quite standard as outlined in Karim's book, the important difference is BoardConfig.mk:
TARGET_NO_KERNEL := true TARGET_NO_BOOTLOADER := true TARGET_CPU_ABI := armeabi-v5te TARGET_CPU_ABI2 := armeabi TARGET_ARCH_VARIANT := armv5te BOARD_USES_GENERIC_AUDIO := true USE_CAMERA_STUB := true BOARD_HAVE_BLUETOOTH := false
Here is a list of various modifications to the AOSP needed to build and run the whole thing:
- There is quite a lot of arm7 optimized code in webrtc library (in the file spl_inl.h) that has to be substituted with standard C code.
- The code has a lot of not aligned accesses so it's important to modify /proc/cpu/alignment to 2 in init.rc.
- Since we are mounting the root file-system via NFS we must check in init.rc that no other partitions are mounted to /data and /system. Some other directories such /mnt/sdcard are not created, we must do this as well in init.rc.
- As detailed in this post there is a bug that prevents web pages to be rendered in the Android browser. It's pretty incredible that such a bug passed the QA at Google, but the fix cited in the post works.
- Because the network is setup before Android runs we must use the Dummy Network Tracker for the connectivity manager. It is configured in frameworks/base/core/res/res/values/config.xml. I had to make some kludges in ConnectivityService.java and NetworInfo.java to force the system believe that network is connected, I'm not sure if this is due to a real problem or, more likely, to a scarce knowledge on my side of the Android frameworks. Perhaps it would be better to use the android-x86 Ethernet Network Tracker, but I wasn't sure how it does interact with a NFS mounted root. As far as network is concerned you have to set the DNS for the frameworks with something like setprop net.dns1 22.214.171.124 and setprop net.dns2 126.96.36.199 in init.rc.
- I've disabled the OpenGL hardware rendering (there's no such thing on the OpenRD) as outlined here (core/java/android/view/HardwareRenderer.java).
The build commands are standard:
. build/envsetup.sh lunch # select openrd-eng make -j4
... and now a lot of patience 🙂
Trying it out
Android works quite well on the OpenRD via NFS (you have to wait a bit on the first boot while the dalvik cache is created via the network and don't expect super-smooth graphics from the frame buffer without acceleration). You can read email, browse the web and use quite a lot of apps. Here is what does the serial terminal show. You can connect to the machine also with adb connect [machine ip] and adb shell.
If you want to try the thing out on the OpenRD you can download the root file system from here. The kernel is in the /boot directory. Just export the file-system via NFS, the kernel uImage via TFTP and with the U-boot commands listed above you're done.
There are still some problems that will be solved (hopefully) in follow-ups to this article.
- Audio is not here. I'm still thinking if it's best to modify Samsug Tuna audio_hw.c provided in the AOSP or wait for the Android PulseAudio patches being released for ICS (the latter would mean no work to be done because ALSA audio is working well in the kernel used).
- The official Market App doesn't work. It dies saying that the network doesn't support a "billing method". This has something to do with the using of the Dummy Network Tracker.
- The galley applications doesn't show the pictures. From the logcat it looks like some OpenGL functions are not implemented (in the software OpenGL renderer I guess ... strange).
- There are sporadic OutOfMemory exceptions while loading bitmaps. I saw this mentioned on some threads on the web but wasn't able to understand it. The problem is sporadic and I'm sure there is still plenty of memory available in the system.