Compile your own Android for your embedded applications
Android is everywhere, in your phones and tablets, but for several years now, this little robot has gone beyond the private sphere of programmers, and is now found in the everyday world. So it is not uncommon to find it in cabs, hospitals, payment terminals, vending machines and so on. So we will see, together, the key steps to build your own Android-based system.
Android is everywhere, in your phones and tablets, but for several years now, this little robot has gone beyond the private sphere of programmers, and is now found in the everyday world.
So it is not uncommon to find it in cabs, hospitals, payment terminals, vending machines and so on. So we will see, together, the key steps to build your own Android-based system.
1. Choose a card
If you can't make your own six-layer circuit board, the idea is to choose a board that best suits the need. The questions to ask yourself are :
- Durability of the product?
- Is there a support service?
- Is Android source code dedicated to the card available?
- What peripherals do I need: GPIO, SPI, I2C, UART, USB, ETHERNET?
- Touch screen or not, resistive or capacitive?
- Storage capacity, CPU performance?
- Mechanical size?
- What price ?
Note that, depending on the identified devices, you may not need a card or compile your own Android!
For example:
- You need a GPS and a 4G connection? Maybe a tablet would do the trick.
- You need an HDMI output and a wifi connection? An Android TV Stick is probably more suitable.
- Do you need specific GPIO, engine controls and hardware drivers? Then yes, a card will probably be the right choice.
For your information, here are some of the distributors we have had the opportunity to work with:
- Olimex : http://www.olimex.com/
- Forlink : http://www.forlinx.net/
- Raspberry : http://www.raspberrypi.org/
- ST : http://www.st.com/
- Rockchip : http://www.rock-chips.com/
- BeagleBoard : http://beagleboard.org/
In terms of price, it is not uncommon to find cards equipped with a resistive screen (a technology often used for kiosks because of its robustness) for a hundred dollars. But here again, be careful! All are not equal in terms of performance, and the user experience could be degraded.
As an example, if you consider the swimming in Android2.2 menus, a Samsung S3C6410 CPU is a bit limited, while a TI Sitara CPU will give a very acceptable result.
2. Android source code
Android is an open source system. The following link gives the method to choose, retrieve and compile an Android repository : http://source.android.com/source/downloading.html
But make no mistake about it, even if it is very generous from Google, the version provided (called AOSP) is intended for the products . Google!
So, as standard, we will find the following targets :
- ARM emulator
- Nexus based
- PandaBoard
You can choose among the following kernels:
# starting point for work on Intel x86_64 chipsets. $ git clone https://android.googlesource.com/kernel/x86_64.git # starting point for work on TI OMAP chipsets. $ git clone https://android.googlesource.com/kernel/omap.git # starting point for NVIDIA Tegra chipsets. $ git clone https://android.googlesource.com/kernel/tegra.git # starting point for Samsung Exynos chipsets. $ git clone https://android.googlesource.com/kernel/exynos.git # starting point for work on Qualcomm MSM chipsets. $ git clone https://android.googlesource.com/kernel/msm.git # starting point for Samsung Hummingbird chipsets. $ git clone https://android.googlesource.com/kernel/samsung.git
In summary, here again, the choice of card is crucial. And, if you don't have the right source code right away, you risk incessant email exchanges between you and your supplier to get the job done. (see the supplier's supplier...)
In the rest of this article, I will take the example of the ok335d card from Forlinx delivered with an Android4.2.
However, most of the information that will follow remains true (with a few adjustments) for other configurations.
3. The Environment
- The environment that gave us the most satisfaction is: Ubuntu 12.04 32bits
- 80 GB of hard disk will be required
- A virtual environment (VirtualBox) is possible, but allow about five hours for the first compilation on a Core i7-2600 @3.40 GHz
Then comes a list of packages to be installed:
sudo apt-get update sudo apt-get install openjdk-7-jdk sudo apt-get install bison g++-multilib git gperf libxml2-utils make zlib1g-dev:i386 zip sudo apt-get install git gnupg flex bison gperf build-essential \ zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev \ libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 \ libgl1-mesa-dev g++-multilib mingw32 tofrodos \ python-markdown libxml2-utils xsltproc zlib1g-dev:i386
Make sure you have the right tool-chain for cross-compilation to your card's CPU. You will probably need to add it to your PATH.
For example, you may need to add it to your PATH:
export PATH=$PWD/prebuilts/gcc/linux‐x86/arm/arm‐eabi‐4.6/bin:$PATH
Tool chain ARM, available here :
$ git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6
4. Compilation of the loader (u-boot)
This is the first element of the chain. That is to say that after the boot ROM (not modifiable by definition), u-boot is the first binary executed (a few hundred kB) at system boot.
Maybe the opportunity to put your first "printf("Hello world"); "
It is mainly the element responsible for initializing some important devices (such as IRQs, memory...) in order to load the Linux kernel in a second step. Often in a separate directory, again it is supposed to be given by the card vendor...?
cd u-boot make ARCH=arm CROSS_COMPILE=arm-eabi- -j8
5. Compiling the kernel (uImage)
The kernel is a branch of Linux 2.6 then 3.0 since Android 4.
cd kernel
This is where you will find the drivers for our hardware configuration.
make menuconfig
But before modifying the ".config" by wandering through these menus, be sure to load the configuration of your card beforehand:
make help # target conf list make ok335xd_evm_android_sdio_defconfig # configure kernel for ok335xd board
To compile :
make ARCH=arm CROSS_COMPILE=arm-eabi- uImage -j8
This will result in the creation of a :
kernel/arch/arm/boot/uImage
Note: If you are not too familiar with compiling Linux kernels, this is the standard procedure, and the Internet is full of tutorials on the subject.
It is at this stage that we will be able to make our own specific drivers (if necessary) for direct access to the hardware. Please note, however, that before tackling the design of a home-made driver, here again several questions need to be asked:
- Is it really a driver that you need? (Hardware registry access inaccessible? Real-time constraint?)
- Isn't this driver already available (or almost)?
- Do you have the precise hardware documentation? (A priori yes, if it's something of yours!)
- Character Driver ? Block Driver ? Network Driver ?
- Kernel module ?
Pilot design is beyond the scope of this article, but here is perhaps a good starting point.
6. Android Compilation
Android is based on a virtual machine named Dalvik that allows to execute Java code bytes (JIT).
But saying "Android is Java"... is a bit reductive. Indeed, compiling Android is also compiling a number of libraries that often bridge between the JAVA and LINUX (JNI) part
To compile :
make TARGET_PRODUCT=am335xevm OMAPES=4.x -j8
The compilation will result in a directory (or set of image files) representing the future File-System.
out/target/product/am335xevm
Just like the "makefile" mechanisms of the two previous sections, Android has its own build system.
Here are the key files used during compilation :
6.1 Android.mk
Like the "Makefile" for "Gnu Make", "Android.mk" is the entry point of the compilation. In the case of our ok335 card, this file contains only one line :
include $(call all-makefiles-under,$(LOCAL_PATH))
And locally we will find in particular :
- AndroidProducts.mk
- BoardConfig.mk
- CleanSpec.mk
6.2 BoardConfig.mk
These are the flags and compilation definitions. Here is an example of what you can find there:
BOARD_USB_CAMERA := true BOARD_EGL_CFG := device/ti/am335xevm/egl.cfg TARGET_CPU_ABI := armeabi-v7a TARGET_CPU_ABI2 := armeabi TARGET_ARCH := arm TARGET_ARCH_VARIANT := armv7-a-neon ARCH_ARM_HAVE_TLS_REGISTER := true TARGET_NO_KERNEL := true #BOARD_HAVE_BLUETOOTH := true #BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := device/ti/am335xevm/bluetooth BOARD_HAVE_BLUETOOTH := false TARGET_NO_BOOTLOADER := true TARGET_NO_RECOVERY := true BOARD_KERNEL_BASE := 0x80000000 #BOARD_KERNEL_CMDLINE := TARGET_NO_RADIOIMAGE := true TARGET_BOARD_PLATFORM := omap3 TARGET_BOOTLOADER_BOARD_NAME := am335xevm USE_OPENGL_RENDERER := true TARGET_HAVE_TSLIB := true
6.3 AndroidProducts.mk
6.3.1 Card information :
PRODUCT_NAME := am335xevm PRODUCT_DEVICE := am335xevm PRODUCT_BRAND := Android PRODUCT_MODEL := AM335XEVM PRODUCT_MANUFACTURER := Texas_Instruments_Inc
6.3.2 List of packages to compile
PRODUCT_PACKAGE += \ LiveWallpapers \ LiveWallpapersPicker \ MagicSmokeWallpapers
The definition of the packages can be found in the "/packages" tree. For example, the file "packages/wallpapers/LivePicker/Android.mk" contains :
LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_REQUIRED_MODULES := android.software.live_wallpaper.xml LOCAL_PACKAGE_NAME := LiveWallpapersPicker LOCAL_CERTIFICATE := platform LOCAL_PROGUARD_FLAG_FILES := proguard.flags
6.3.4 Files to be copied as is, in the future File-System
PRODUCT_COPY_FILES += \ device/ti/am335xevm/init.am335xevm.rc:root/init.am335xevm.rc \ device/ti/am335xevm/media_codecs.xml:system/etc/media_codecs.xml
6.3.5 General properties
PRODUCT_PROPERTY_OVERRIDES += \ ro.ethernet.default_on=true \ ro.hw.ethernet.onboard=true \ hw.hasethernet=true
The sum of the properties will be written in the file "system/build.prop" of the future File-System.
7. Example of customization: Change wifi driver
Here is, in two lines, how wifi works under Android :
- Under Linux, a deamon named "wpa_supplicant" is initialized (in init.rc) to control the wifi driver (through NL80211 for example).
- Under Android, a pipe of this deamon is realized in "hardware/libhardware_legacy/wifi/wifi.c" in order to provide a Java class android.net.wifi
So we will have to modify Android and its kernel. Here are the steps we should go through:
- At the kernel level, add the driver corresponding to your chipset (if it is not present, you will have to add it).
- Adjust the BOARD_WPA_SUPPLICANT_DRIVER section in BoardConfig.mk accordingly (is this a NL80211, WEXT driver?).
- Adjust/Add a rule in the "AndroidProduct.mk" cascade to copy your own configuration file "wpa_supplicant.conf" to the future File-System "\etc\wifi\ "
- Add a rule in the ""AndroidProduct.mk"" cascade to copy the potential proprietary firmware in the future File-System ""\system\etc\firmware\ "".
For more details: http://blog.linuxconsulting.ro/2010/04/porting-wifi-drivers-to-android.html
Other examples of customization : http://www.omappedia.com/wiki/Android_How-tos
8. The Android File System patch, an alternative?
When we look at the previous points, we notice that the result of the Android compilation are image files of the future File-System. Consequently, it is quite conceivable to:
- Recover the image (typically recovery.img) already present on the map.
- Open it with appropriate tools (mkimage, yaffs)
- Create a patch by adding a kernel module (.ko), modifying the init.rc file, add/remove/modify apk, etc. ...
- close recovery.img then re-install on the board.
In this case, there is simply no need to compile Android! A most appreciable time saving!
9. Logo, Buttons and Kiosk
9.1 Logo
When we talk about customization, the first thing we think about is to be able to change the animation when starting Android. So here is the file to create/modify in the future File-Sytem :
/system/media/bootanimation.zip
See: http://forum.xda-developers.com/showthread.php?t=1852621 for more details
9.2 Kiosque
If Android is used for a very specific application, it will probably be necessary to replace the default Launcher.
A Launcher is the application that starts first, and is reactivated when you press the ""HOME"" button, often called :
/system/data/app/Launcher.apk
It differs from other Android apk not by its name, but by its manifest.xml :
<activity android:name="" com.test.mylauncher="">
<intent-filter>
<action android.intent.action.main="" android:name="">
<category android.intent.category.home="" android:name="">
<category android.intent.category.default="" android:name="">
</category></category></action></intent-filter>
</activity>
Note: If more than one apk is defined as a launcher, Android will ask the user to choose. More info here: http://www.andreas-schrade.de/2015/02/16/android-tutorial-how-to-create-a-kiosk-mode-in-android/
9.3 Buttons
Hardware buttons are specified here :
/system/usr/keylayout/*.kl
for more info : https://source.android.com/devices/input/key-layout-files.html
10. Installation
The way to "flash" a card, i.e. to apply the results of the previous points 4, 5, 6 in a non-volatile memory (typically NAND memory), depends on the chosen card.
It is often the ROM-Boot (engraved in silicon) that will offer this service. There can be several types of transfers possible :
- UART
- TFTP
- SDCARD
- ...
Usually, a switch on the board (or activity on the UART at startup) switches the ROM-Boot to download mode with a preset transfer type. In the case of the ok335 card for example, the switch allows to ask the ROM-Boot to copy the files present on a SDCARD (FAT32) to the NAND memory of the card.
Here are the files present on the SD card :
- u-boot.img - 265kB - microloader
- uImage - 4212kB - e kernel
- ubi.img- 146304kB - FileSystem Android
11. Links
- http://www.xda-developers.com/
- http://www.cyanogenmod.org/
- http://elinux.org/Android_Device