Building and Deploying Android AOSP 6.01 for the Wandboard

While our guide of how to build deploy vanilla AOSP on the Wandboard has helped many to understand more about the Android and Linux build tools, it is often required for applications to have hardware graphics acceleration.

The following guide shows how to download the Wandboard AOSP source, how to compile and deploy it and how to reconfigure Android for custom purpose.

  • Host Build System: Ubuntu 16.04 LTS 64 bit
  • Hardware: Wandboard Quad revision C1
  • Kernel Version: 3.14.52 (way behind mainline, yet this is required for the hw graphics acceleration)
  • Bootloader: u-boot (imx branch) v2015.04
  • Android Version: 6.0.1 from the official Wandboard website

Additional Hardware requirements:

  • USB-Serial Converter and Nullmodem Cable
  • Micro SD Card (Class 10 for decent I/O performance)
  • 5V wall plug (make sure it is 2A+ capable)

The source code for all kernel / u-boot and AOSP can be found on wandboard.org as tarball here, direct link to the tarball here.

Before starting, a couple of dependencies need to be installed in order to compile the source.

First off install the required java version, which is openjdk-7-jdk. However the package is not available in the default 16.04 Ubuntu repos, the easiest way to install the sources is from the ppa (thread on askubuntu here).

Please note that while the official AOSP documentation suggest installing openjdk-8-jdk, we have been more successful with openjdk-7-jdk on this particular build.

sudo add-apt-repository ppa:openjdk-r/ppa  
sudo apt-get update   
sudo apt-get install openjdk-7-jdk

If you have previously installed one or more versions of java it is necessary to change at least the java and javac executable to the appropriate version. On Ubuntu, “update-alternatives” is used for this purpose.

# first check your java version
java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)

# In this case our java version is 1.6 oracle
# We will use "update-alternatives" to change to the newly installed
# java 7 openjdk

sudo update-alternatives --config java

There are 4 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                            Priority   Status
------------------------------------------------------------
  0            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      auto mode
  1            /usr/lib/jvm/java-6-oracle/jre/bin/java          1072      manual mode
* 2            /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java   1071      manual mode
  3            /usr/lib/jvm/java-7-oracle/jre/bin/java          1073      manual mode
  4            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      manual mode

# and do the same for javac

sudo update-alternatives --config javac

There are 4 choices for the alternative javac (providing /usr/bin/javac).

  Selection    Path                                         Priority   Status
------------------------------------------------------------
  0            /usr/lib/jvm/java-8-openjdk-amd64/bin/javac   1081      auto mode
  1            /usr/lib/jvm/java-6-oracle/bin/javac          1072      manual mode
* 2            /usr/lib/jvm/java-7-openjdk-amd64/bin/javac   1071      manual mode
  3            /usr/lib/jvm/java-7-oracle/bin/javac          1073      manual mode
  4            /usr/lib/jvm/java-8-openjdk-amd64/bin/javac   1081      manual mode

# verify the new version
java -version

java version "1.7.0_95"
OpenJDK Runtime Environment (IcedTea 2.6.4) (7u95-2.6.4-3)
OpenJDK 64-Bit Server VM (build 24.95-b01, mixed mode)

Note that the Android build system will look for an environment variable “$JAVA_HOME” and – if it is defined – use this particular java installation (disregarding any possible changes made with update-alternatives). If you have installed other java versions, it is possible that this variable is set somewhere inside /etc/profile.d/ or similar.

# check if JAVA_HOME variable is set
echo $JAVA_HOME
/usr/lib/jvm/java-6-oracle

# In our case, JAVA_HOME is already defined

# We can either unset it temporarily in our current shell before building Android
unset JAVA_HOME

# Or add our own JAVA_HOME export to .bashrc or .profile
# Or search and remove the definitions inside /etc folders
# (in that case you need to logout and login again)
cd /etc
grep -sr "JAVA_HOME" .
profile.d/jdk.sh:export JAVA_HOME=/usr/lib/jvm/java-6-oracle
profile.d/jdk.csh:setenv JAVA_HOME /usr/lib/jvm/java-6-oracle
ca-certificates/update.d/jks-keystore:export JAVA_HOME=/usr/lib/jvm/$jvm
ca-certificates/update.d/jks-keystore:PATH=$JAVA_HOME/bin:$PATH

There are a couple of packages that are also required and detailed at source.android.com.

sudo apt-get install git-core gnupg flex bison gperf build-essential \
  zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \
  lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache \
  libgl1-mesa-dev libxml2-utils xsltproc unzip

At this point, starting a build would result in below error:

clang: error: linker command failed with exit code 1 (use -v to see invocation)
build/core/host_shared_library_internal.mk:51: recipe for target 'out/host/linux-x86/obj32/lib/libart.so' failed
make: *** [out/host/linux-x86/obj32/lib/libart.so] Error 1

Thankfully this problem has been patched for newer Android releases, the patch can be found in this post.

The first couple of lines of the file build/core/clang/HOST_x86_common.mk needs to be changed to look like this:

CLANG_CONFIG_x86_DARWIN_HOST_EXTRA_CFLAGS := \
  -integrated-as

CLANG_CONFIG_x86_DARWIN_HOST_EXTRA_CFLAGS += -fstack-protector-strong
endif

ifeq ($(HOST_OS),linux)
CLANG_CONFIG_x86_LINUX_HOST_EXTRA_ASFLAGS := \
  --gcc-toolchain=$($(clang_2nd_arch_prefix)HOST_TOOLCHAIN_FOR_CLANG) \
  --sysroot $($(clang_2nd_arch_prefix)HOST_TOOLCHAIN_FOR_CLANG)/sysroot \
  -B$($(clang_2nd_arch_prefix)HOST_TOOLCHAIN_FOR_CLANG)/x86_64-linux/bin

Adjusting AOSP configuration for deployment

Besides fixing the above issue, it is necessary to apply a few modifications to the default configuration of the android framework as well as the mounting table found in fstab.freescale.

First let’s have a look at the framework config

# change into the device folder from the top directory
cd device/fsl/wandboard

# edit defaults.xml of the SettingsProvider
gedit overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml

Add the below properties to the file to avoid the screen timing out:

    <bool name="def_stay_on_while_plugged_in">true</bool>
    <integer name="def_screen_off_timeout">30000</integer>

Above properties prevent Android from going to sleep. As it turns out in this unmodified version, going to sleep will cause the system to reboot instead.

Furthermore, when changing the layout of the SD-Card partitions, a change in the fstab is required. The below changes match the partition layout further down the line.

Have a look at the mount table fstab.freescale in the device directory and adjust it to the below content:

# change into the device folder from the top directory
cd device/fsl/wandboard

# edit fstab.freescale
gedit fstab.freescale
# Android fstab file.
#<src>                                                  <mnt_point>         <type>    <mnt_flags and options>                       <fs_mgr_flags>
# The filesystem that contains the filesystem checker binary (typically /system) cannot
# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK

/devices/soc0/soc.0/2100000.aips-bus/2190000.usdhc/mmc_host* auto auto defaults voldmanaged=sdcard:auto
/devices/soc0/soc.0/2100000.aips-bus/2184200.usb/ci_hdrc.1*  auto auto defaults voldmanaged=usb:auto
/devices/soc0/soc.0/2200000.sata/ata1* auto auto defaults voldmanaged=sata:auto


/dev/block/mmcblk2p2    /system      ext4    rw,barrier=1                                                                               wait,verify
/dev/block/mmcblk2p4    /data        ext4    nosuid,nodev,nodiratime,noatime,nomblk_io_submit,noauto_da_alloc,errors=panic    wait,check
/dev/block/mmcblk2p3    /cache       ext4    nosuid,nodev,nomblk_io_submit                                                    wait,check
/dev/block/zram0 none swap defaults zramsize=314572800

After these changes, you are now ready to compile the Kernel, the Uboot bootloader as well as the Android OS (consisting mainly of system image and ramdisk).

There are actually two ways of how to compile Android at this stage. Under the folder /cookers you will find an environment setup that will allow you to just use the “cook” command which in turn calls make in all kernel, uboot and AOSP. While this might be a good idea for a quick build, there is added value in compiling each of the parts separately in order to gain a deeper understanding of configuring building and deploying the various parts involved.

Building with the “cook” script

These commands allow the build to be kicked off without any further understanding of the source:

# change to the root directory of the Android sources
source cookers/env.bash.imx6.edm1cf-sd.wandboard.hdmi
cook -j4

The cook script will select the wandboard configuration for all bootloader, kernel and AOSP. Again make sure that your JAVA_HOME path variable is unset before executing cook.

After building bootloader, and kernel, the Android build starts

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=6.0.1
TARGET_PRODUCT=wandboard
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
TARGET_CPU_VARIANT=cortex-a9
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-4.4.0-47-generic-x86_64-with-Ubuntu-16.04-xenial
HOST_BUILD_TYPE=release
BUILD_ID=1.0.0-ga-rc6
OUT_DIR=out
============================================

Alternatively the parts of the system may be built manually.

Building with the kernel, bootloader and AOSP the traditional way

In order to start the AOSP build, the u-boot bootloader and Linux kernel need to be compiled first, because the wandboard target recipe has dependencies on both u-boot and kernel binaries.

Building the Linux kernel

# change into the Android top directory (/opt/android/wand in our case)
# ... and set up CROSS_COMPILE and ARCH
export ARCH=arm
export CROSS_COMPILE="/opt/android/wand/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-"

# change into kernel directory
cd kernel_imx

# if you would like to clean a prior build
make distclean

# if you want to clean the current configuration (.config) as well
make mrproper

# prepare the kernel configuration
make wandboard_android_defconfig

# edit the config to your liking to add or remove device drivers
make menuconfig

# build the kernel, -j tells the make file system how many jobs to launch in parallel
make -j4 zImage

# the output after building the kernel successfully will look something like this
  ...
  LD      arch/arm/boot/compressed/vmlinux
  OBJCOPY arch/arm/boot/zImage
  Kernel: arch/arm/boot/zImage is ready

#### make completed successfully (02:43 (mm:ss)) ####

# also build modules and dtbs

make -j4 modules
make dtbs

Building the u-boot bootloader

# change to aosp top dir
# and make sure ARCH and CROSS_COMPILE are set
export ARCH=arm
export CROSS_COMPILE="/opt/android/wand/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-"

# change into u-boot directory
cd bootable/bootloader/uboot-imx

# prepare the configuration
make wandboard_defconfig

# build the bootloader
make -j4

# on success the last output lines will look like this
  ...
  LD      spl/u-boot-spl
  OBJCOPY spl/u-boot-spl.bin
  CFGS    arch/arm/imx-common/spl_sd.cfg.cfgtmp
  MKIMAGE SPL

#### make completed successfully (10 seconds) ####

Building AOSP

# change to the aosp top dir
cd /opt/android/wand

# init environment
. build/envsetup.sh

# run 'lunch' and select
# [23] wandboard-eng
# as the target product
lunch

# you may also directly run 
lunch wandboard-eng
# or
lunch 23

# now check the Android configuration with
printconfig
# ... which should look something like this
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=6.0.1
TARGET_PRODUCT=wandboard
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
TARGET_CPU_VARIANT=cortex-a9
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-4.4.0-47-generic-x86_64-with-Ubuntu-16.04-xenial
HOST_BUILD_TYPE=release
BUILD_ID=1.0.0-ga-rc6
OUT_DIR=out
============================================


# double check JAVA_HOME var

echo $JAVA_HOME
/usr/lib/jvm/java-7-openjdk-amd64

# JAVA_HOME must be either unset
# or point to /usr/lib/jvm/java-7-openjdk-amd64
# otherwise the build might not start

# start compile
make -j8

# once finished the output should look something like this
Creating filesystem with parameters:
    Size: 624152576
    Block size: 4096
    Blocks per group: 32768
    Inodes per group: 7632
    Inode size: 256
    Journal blocks: 2380
    Label: system
    Blocks: 152381
    Block groups: 5
    Reserved block group size: 39
Created filesystem with 1530/38160 inodes and 93182/152381 blocks
build_verity_tree -A aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7 out/target/product/wandboard/obj/PACKAGING/systemimage_intermediates/system.img /tmp/tmpx_98xE_verity_images/verity.img
system/extras/verity/build_verity_metadata.py 624152576 /tmp/tmpx_98xE_verity_images/verity_metadata.img 5339aa8e5e3793d45681e7238d0cda3ee688efd07db47ab27fd942559534db50 aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7 /dev/block/mmcblk2p5 out/host/linux-x86/bin/verity_signer build/target/product/security/verity.pk8
append2simg out/target/product/wandboard/obj/PACKAGING/systemimage_intermediates/system.img /tmp/tmpx_98xE_verity_images/verity_metadata.img
append2simg out/target/product/wandboard/obj/PACKAGING/systemimage_intermediates/system.img /tmp/tmpx_98xE_verity_images/verity.img
Install system fs image: out/target/product/wandboard/system.img
out/target/product/wandboard/system.img+out/target/product/wandboard/obj/PACKAGING/recovery_patch_intermediates/recovery_from_boot.p maxsize=642318336 blocksize=4224 total=378917909 reserve=6488064
simg2img out/target/product/wandboard/system.img out/target/product/wandboard/system_raw.img;

After building AOSP, the ramdisk ramdisk.img as well as the system partition system.img are generated in the appropriate out folder “./out/target/product/wandboard”.

Deploying Bootloader, Kernel and Ramdisk

Deploying the produced binaries on an SD-Card will allow AOSP to be booted on the wandboard.

While the included cookers script suggest to create a total of 9 partitions, we opt to deploy the system on an SD-Card with only 4 partitions.

In order to format the SD-Card properly, we recommend to use UI based partition manager “gparted”.

# install gparted if not installed already
sudo apt-get install gparted

# launch gparted
sudo gparted

# step by step guide
# select SD-Card (be careful! make sure it is the right block device, making mistakes in this step and modifying wrong block devices may cause damage to your hard drive beyond repair)
# 1. create first primary partition at offset 8MiB (before comes bootloader), size 33MiB, choose fat32, label BOOT
# 2. create second primary partition right after BOOT, size 1024MiB, ext4, label SYSTEM
# 3. create third primary partition right after SYSTEM, size 1024MiB ext4, label CACHE
# 4. create fourth primary partition right after CACHE, size is the remaining space on your SD-Card, label DATA

Below screenshot shows the partition table of the SD-Card

partitions on the sd card for deploying Android 6.0.1 on the Wandboard Quad

Once the SD-Card is formatted, it is time to mount the BOOT and SYSTEM partition and deploy the files. The data and cache partition remain empty for deployment, on first boot the data partition will be populated by Android.

Deploying Android onto an SD-Card

It is essential to understand that deployment of Android on any media is highly customisable. While most Android images found on embedded platforms follow the pattern to deploy partitions such as modem, recovery or external sdcard, none of these are mandatory.

The Android OS expects though to have a /cache and /data partition as well as a mount point for /system.

While by default a ramdisk is extracted into memory and mounted as root partition, even that behavior may be changed in favor of one root partition containing both ramdisk content as well as /system directory.

In our case we will favor to use a ramdisk and a separate /system partition.

Furthermore it is necessary to understand that while the /system partition contents have been compiled into the out/target/product/wandboard/system directory, the permissions and mods of the contents are not set appropriate for deployment. However these files are also written into the disk images out/target/product/wandboard/system.img and the raw image out/target/product/wandboard/system_raw.img. While system.img cannot be easily mounted on an Ubuntu host, system_raw.img is a plain ext4 partition image of the Android /system directory containing all the right file mods and permissions.

The system_raw.img can be recompiled using the simg2img utility which is also helpful when restoring system partitions directly from a device or rom.

Deploying the System partition

# mount system_raw.img
# change to source root
croot
# or simply
cd /opt/android/wand

# create a mount point and mount the system image
mkdir system_mnt
sudo mount out/target/product/wandboard/system_raw.img system_mnt

# check if the image has been mounted
mount
/android/out/target/product/wandboard/system_raw.img on /android/system_mnt type ext4 (rw,relatime,data=ordered)

# copy the files over to the SD-Cards system partition
cd system_mnt
sudo cp -a * /mnt/$USER/SYSTEM/
sync

Copying these files and syncing may take quite a while depending on your SD-Card transfer rate.

Deploying the Boot partition

In order to set up the boot partition, bootloader, ramdisk and device tree binaries need to be copied into the BOOT partition.

# change to root dir of aosp
cd /opt/android/wand

# copy u-boot bootloader
sudo cp bootable/bootloader/uboot-imx/u-boot.img /media/$USER/BOOT/

# copy the Linux kernel
sudo cp kernel_imx/arch/arm/boot/zImage /media/$USER/BOOT/

# copy the device tree binaries for wandboard quad/dual
sudo cp kernel_imx/arch/arm/boot/dts/imx6q-wandboard.dtb /media/$USER/BOOT/
sudo cp kernel_imx/arch/arm/boot/dts/imx6dl-wandboard.dtb /media/$USER/BOOT/

# convert the ramdisk to a u-boot image file named uramdisk.img
# and copy it to the boot partition
sudo mkimage -A arm -O linux -T ramdisk -C none -a 0x10800800 -n "Android Root Filesystem" -d ./out/target/product/wandboard/ramdisk.img ./out/target/product/wandboard/uramdisk.img
sudo cp ./out/target/product/wandboard/uramdisk.img /media/$USER/BOOT/

# unmount everything
sync
sudo umount /media/$USER/*

# flash the 1st stage bootloader
# find the SD-Card block device name /dev/sdX
lsblk

sudo dd if=bootable/bootloader/uboot-imx/SPL of=/dev/sdX bs=1k seek=1
sync

After this procedure the SD-Card is ready to boot and will start Android. Using an USB-to-serial adapter, it is now possible to observe the system booting using your preferred serial terminal program (minicom, screen, putty, etc.).

# start and setup minicom
sudo minicom -s wandboard

# select 115200, 8N1, no hw flow control, no sw flow control
# save and exit

Hopefully this guide has helped you getting started on working on your own AOSP build on the Wandboard. If you liked the tutorial please let us know by sharing it on G+ and throw us a +1.

One Reply to “Building and Deploying Android AOSP 6.01 for the Wandboard”

  1. Hello Manuel,

    good tutorial to build Android Source for the Wandboard.
    I try to build with the “cook” script, but it get errors, . . . any idea, what is the Problem? Thanks.

    rbn@rbn-Latitude-E6420:~/opt/android/wand$ source cookers/env.bash.imx6.edm1cf-sd.wandboard.hdmi
    rbn@rbn-Latitude-E6420:~/opt/android/wand$ cook -j4
    #
    # configuration written to .config
    #
    scripts/kconfig/conf –silentoldconfig Kconfig
    CHK include/config.h
    GEN include/autoconf.mk
    GEN include/autoconf.mk.dep
    arm-eabi-gcc: error trying to exec ‘cc1’: execvp: No such file or directory
    arm-eabi-gcc: error trying to exec ‘cc1’: execvp: No such file or directory
    scripts/Makefile.autoconf:71: recipe for target ‘include/autoconf.mk’ failed
    make[1]: *** [include/autoconf.mk] Error 1
    make[1]: *** Waiting for unfinished jobs….
    GEN spl/include/autoconf.mk
    scripts/Makefile.autoconf:47: recipe for target ‘include/autoconf.mk.dep’ failed
    make[1]: *** [include/autoconf.mk.dep] Error 1
    arm-eabi-gcc: error trying to exec ‘cc1’: execvp: No such file or directory
    scripts/Makefile.autoconf:74: recipe for target ‘spl/include/autoconf.mk’ failed
    make[1]: *** [spl/include/autoconf.mk] Error 1
    make: *** No rule to make target ‘include/config/auto.conf’, needed by ‘include/config/uboot.release’. Stop

Leave a Reply

Your email address will not be published. Required fields are marked *


*