Spiria logo.

Compile your own Android for your embedded applications

July 15, 2015.

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:

Boards Image

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

decorative

  • 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)

decorative

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

menuconfig_img

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

decorative

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

decorative

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