Building and Deploying Vanilla/AOSP Android 4.4.4 for the Wandboard

In this post we are going to build and deploy Android Kitkat for the Wandboard Quad. The instructions are mostly identical for the Wandboard Dual, although you will need a different u-boot bootloader configuration, and a different dtb file. With the current Android 4.4.4 build we are able to use ethernet, wifi in client and AP mode, as well as ALSA sound. Bluetooth and hardware accelerated graphics is not yet accomplished.

  • Host Build System: Ubuntu 13.10 (64 Bit)
    It is important to use a 64 Bit version, otherwise, it is not possible to build Android.
  • Hardware: Wandboard Quad revision B1
  • Kernel version: 3.16 rc5
    We will use the latest kernel provided by Robert Nelson
  • Bootloader: u-boot bootloader by Denx
    We will also download and patch as per instructions provided by Robert Nelson.
  • Android version: 4.4.4_r1 AOSP
  • An USB to serial converter for communicating with the Wandboard
    Unless your computer has a serial port of course.
  • A microSD card
    We recommend at least class 10, it really makes a big difference. A size of 2GB should be enough.

For this tutorial, we will have 3 main source code repositories, namely Android, u-boot and Linux kernel sources. It is assumed that we download the Android source code, and place the u-boot and Kernel sources in their respective sub-folders “u-boot” and “armv7-multiplatform” inside the Android source‘s root. While the exact location does not matter, we will use /opt/android as an example here. Since we are going to use a cross-compiler from Android for building the bootloader, it makes sense to first download all the source code repositories before starting with this tutorial.

# Download Android source /opt/android
mkdir /opt/android
cd /opt/android
repo init -u https://android.googlesource.com/platform/manifest -b android-4.4.4_r1
repo sync

# Download u-boot source into /opt/android/u-boot
cd /opt/android
git clone git://git.denx.de/u-boot.git

# Download Linux kernel sources into /opt/android/armv7-multiplatform
cd /opt/android
git clone https://github.com/RobertCNelson/armv7-multiplatform.git

u-boot bootloader

We will start by downloading, building and deploying the u-boot bootloader to a microSD card. Not to take anything away, this step is identical to the Wandboard u-boot instructions provided by Robert Nelson, thanks a lot for sharing! For completeness, I will add all instructions here as well.

cd /opt/android
git clone git://git.denx.de/u-boot.git
cd u-boot/
git checkout v2014.07 -b tmp
# Patching
wget -c https://raw.githubusercontent.com/eewiki/u-boot-patches/master/v2014.07/0001-wandboard-uEnv.txt-bootz-n-fixes.patch
patch -p1 < 0001-wandboard-uEnv.txt-bootz-n-fixes.patch
# start build
export ARCH=arm
export CROSS_COMPILE=../prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin/arm-eabi-
make distclean
make wandboard_quad_config
make -j8

If everything works fine, you should get a binary called u-boot.imx. This is our bootloader which must be placed on the SD card. Different chipsets have different mechanisms for obtaining the bootloader. For instance, on the Beaglebone a file called MLO and another u-boot binary is to be placed on the first FAT partition. The reason for this is that the location and name (‘MLO’) is unalterably burnt into the chip. For the Wandboard with its i.MX6 chipset, the process is slightly different. The u-boot.imx bootloader file needs to be placed at an offset of exactly 1024 bytes into the SD card’s storage, and is itself around 300KB in size. Therefore, it is important that we leave some space before the beginning of the first partition. Let’s just do that: insert an SD card into your host computer, and use the partitioning program of your choice. A nice and easy tool is “gparted” for instance.

On our SD card, we want to create 3 partitions:

  1. File system: ext4
    Size: 512MiB
    Label: RFS
    Free space preceding: 10MiB
  2. File system: ext4
    size: 512MiB
    Label: CACHE
  3. File system: ext4
    size: (rest of disk space)
    Label: DATA

You could of course use less space preceding before the first partition, this is just to be super safe. Here is a screenshot of what it should look like, when you are using gparted.

serverbox_wandboard_gparted

Notice the unallocated region before the first partition. Also, note the device name in the upper right corner (“/dev/sde” in this case). When you are done with partitioning, we will copy the bootloader onto the SD card with the Linux “dd” command. Be very careful that you do not accidentally write to your computer’s hard disk instead. You should already know the SD card’s device name from the partitioning tool used earlier. Before continuing however, it is still a good idea to run “lsblk”, which will again list all the attached disk drives. Only execute the “dd” command, if you are certain that this is your SD card.

$ lsblk
...
└─sdb5   8:21   0  11.7G  0 part 
sdc      8:32   0 465.8G  0 disk 
├─sdc1   8:33   0   100M  0 part 
└─sdc2   8:34   0 465.7G  0 part 
sde      8:64   1   7.4G  0 disk 
├─sde1   8:65   1   512M  0 part 
├─sde2   8:66   1   512M  0 part 
└─sde3   8:67   1   6.4G  0 part
# In this case, we would replace sdX with sde
$ sudo dd if=u-boot.imx of=/dev/sdX bs=512 seek=2
$ sync

You can now try if the bootloader is recognized correctly. For this you will need to connect the Wandboard’s serial port with your computer, and use a serial terminal program such as “minicom”. The serial port settings should be

  • Bps/Par/Bits: 115200 8N1
  • Hardware Flow Control: No
  • Software Flow Control: No
  • Serial Device: probably /dev/ttyUSB0 or /dev/ttyACM0

Insert the SD card into the Wandboard and power up the board. Of course, since we do not have a Linux kernel installed yet, nothing good will come of this :) Nevertheless, some output similar to the following should be visible:

U-Boot 2014.07-dirty (Jul 23 2014 - 13:23:55)

CPU:   Freescale i.MX6Q rev1.2 at 792 MHz
Reset cause: POR
Board: Wandboard
I2C:   ready
DRAM:  2 GiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 1
...

Linux kernel

The next thing we need is a Linux kernel binary. Once more, check out Robert Nelson’s instructions.

cd /opt/android
git clone https://github.com/RobertCNelson/armv7-multiplatform.git
cd armv7-multiplatform
git checkout origin/v3.16.x -b tmp
./build_kernel.sh

The last step will download the Linux source code together with minimal patches. It will also download a recent cross-compiler. If you want to save bandwidth, you could also edit the system.sh file and adjust the CC variable, and in that case, your own cross compiler would be used instead. Furthermore, the configuration process is started, and after some time, you should be greeted with a menuconfig screen. Since we are aiming to run Android later on, navigate to the Android section and include the Android log driver (which is used for logcat) statically in the kernel. The Android section is found under Device Drivers – Staging drivers – Android. Navigate to “Android log driver” and hit “Y” or toggle spacebar until an asterisk is visible at the beginning of the line.

serverbox_wandboard_04_android_log_driver

For sound support, choose:

  • Device Drivers
  • <*> Sound Card Support
  • <*> Advanced Linux Sound Architecture
  • <*> ALSA for SoC audio support
  • SoC Audio for Freescale CPUs ->
  • <*> Soc Audio for Freescale i.IMX CPUs and <*> SoC Audio support for i.MX boards with sgtl5000

serverbox_wandboard_soc_audio

Furthermore, you may want to enable UVC support for USB cameras and alike

  • Device Drivers
  • <*> Multimedia support
  • <*> Media USB Adapters
  • <*> USB Video Class (UVC)

serverbox_wanboard_uvc

Then hit ESC repeatedly and choose to save the current configuration.

After finishing the configuration, the compile process also starts automatically and if everything works well, you will end up with a compressed kernel image in
/opt/android/armv7-multiplatform/KERNEL/arch/arm/boot/zImage
There is also a device tree blob/binary found in
/opt/android/armv7-multiplatform/KERNEL/arch/arm/boot/dts/imx6q-wandboard.dtb
(or imx6dl-wandboard.dtb for Wandboard Dual)

Deploying Linux kernel and uEnv.txt

Our u-boot bootloader already has a lot of built-in environment variables. Have a look at u-boot/include/configs/wandboard.h for more information. The basic startup sequence is as follows:

  • Each partition of the SD card will be searched for an environment file under /boot/uEnv.txt
  • If an uEnv.txt file is found, its contents are imported to the current u-boot environment. (This also allows for overriding certain variables)
  • If the uEnv.txt file contains a variable named “uname_r”, the function “uname_boot” is called.
  • Within uname_boot, a compressed kernel binary is assumed to be under /boot/vmlinuz-{uname_r}
  • The name of a device tree binary may be specified with the variable “dtb”. The file itself will then be searched in /boot/dtbs/{uname_r}/{dtb} and /boot/{dtb} amongst other locations.
  • At the end of uname_boot, “run mmcargs” is called.

To edit the kernel command line for instance, you could modify the file u-boot/include/configs/wandboard.h by setting “cmdline=…” and recompile u-boot. However, that is of course an impractical approach, especially for development purposes. To include a custom cmdline parameter, it is much easier to create an uEnv.txt file and put it on the first partition of our SD card under /boot/uEnv.txt. Within the uEnv.txt we are free to set our own parameters. As described above, mmcargs will be executed ultimately.

The default value of mmcargs as defined in u-boot/include/configs/wandboard.h is…

mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype} ${cmdline}

… and including your own parameters is done by setting “optargs” and “cmdline” in the uEnv.txt file. It would also be possible of course, to completely override “mmcargs” or even “uname_boot”.

An example uEnv.txt file would be:

uname_r=3.16
dtb=imx6q-wandboard.dtb
optargs=androidboot.console=ttymxc0 androidboot.hardware=wandboard-quad
cmdline=init=/init

Either create your own, or download this example uEnv.txt file, and copy it to the SD card. Notice, that the variable uname_r is set to 3.16. Therefore, our kernel binary should be named vmlinuz-3.16 as described above.

sudo mkdir /media/user/RFS/boot
sudo cp Downloads/serverbox_wandboard_uEnv.txt /media/user/RFS/boot/uEnv.txt
sudo cp /opt/android/armv7-multiplatform/KERNEL/arch/arm/boot/zImage /media/user/RFS/boot/vmlinuz-3.16
sudo cp /opt/android/armv7-multiplatform/KERNEL/arch/arm/boot/dts/imx6q-wandboard.dtb /media/user/RFS/boot
sync

Again, try to boot the Wandboard with the current SD card. It should find the uEnv.txt as well as the compressed kernel and dtb file. After a few seconds, you will get a kernel panic “not syncing: No working init found”, which was to be expected. After all, there is no init binary on our SD card, yet…

Building Android

This is where it gets exciting :) Download the Android source code with the repo tool. In this tutorial, we are using the release branch “android-4.4.4_r1″.

mkdir /opt/android/
cd /opt/android/
repo init -u https://android.googlesource.com/platform/manifest -b android-4.4.4_r1
repo sync

Downloading will probably take a few hours, unless you already have a local Android mirror! Have a look at the official instructions for setting up your very own Android mirror, in case you are interested.

We started development by modifying the generic “mini_armv7a_neon” product under device/generic/armv7-a-neon. You can download our armv7-a-neon folder from here. Just copy its contents over your fresh install, this way, you can use git to see all the changes and also revert back if needed.

cd ~/Downloads
# download
wget http://android.serverbox.ch/wp-content/uploads/2014/07/serverbox_wandboard_android.tar
# extract
tar -xf serverbox_wandboard_android.tar
# copy over original folder
cp -r armv7-a-neon/* /opt/android/device/generic/armv7-a-neon
# check
cd /opt/android/device/generic/armv7-a-neon
git status
# git status should show
# 4 modified and
# 3 untracked files

A few more changes are needed if you also want to be able to create a wireless access point (AP mode). There are two functions “wifi_get_fw_path” and “wifi_change_fw_path” from hardware/libhardware_legacy/wifi/wifi.c which need modifications. Just add a return statement right at the beginning of each, like so:

cd hardware/libhardware_legacy
vim wifi/wifi.c
const char *wifi_get_fw_path(int fw_type)
{
  return "dummy";
  ..
}
 
int wifi_change_fw_path(const char *fwpath)
{
  return 0;
  ..
}

On some devices, there are different wifi module firmwares for “normal” STA mode, access point (AP), and peer-to-peer (P2P) mode. And those firmwares are dynamically loaded, depending on which mode is active. However, on the Wandboard only one firmware is used for all modes (although we did not test P2P specifically). Therefore, the above functions can be stubbed as described. Note that the firmware in armv7-a-neon/root_overlay is an APSTA variant with version 4.220.48, which was originally downloaded from this Wandboard forum post.

The external/wpa_supplicant_8 project contains the source code for both wpa_supplicant and hostapd version 2.1-devel. For AP mode to work properly, we need to replace hostapd with the newer 2.2 version directly from http://w1.fi.

rm -rf /opt/android/external/wpa_supplicant_8/hostapd
cd ~/Downloads
wget http://w1.fi/releases/hostapd-2.2.tar.gz
tar -xzf hostapd-2.2.tar.gz
cd hostapd-2.2
mv hostapd /opt/android/external/wpa_supplicant_8/
mv src /opt/android/external/wpa_supplicant_8/hostapd/

Furthermore, if you also want to activate AP mode via the Android UI, comment out the “updateBluetoothState” function call in the Settings application:

cd packages/apps/Settings
vim src/com/android/settings/TetherSettings.java
private void updateState(String[] available, String[] tethered,
            String[] errored) {
        updateUsbState(available, tethered, errored);
        // Quick hack to fix NullPointerException
        //updateBluetoothState(available, tethered, errored);
    }

The above fix is needed because we do not have proper Bluetooth support yet, and when the “Portable hostspot” tab is opened via the Settings application, the above function call would result in a Java NullPointerException.

Finally, we can start the Android build process!

cd /opt/android/
. build/envsetup.sh
choosecombo 1 mini_armv7a_neon 3
make -j8

Depending on your host computer, this may take up to a few hours. The last output you will get if everything succeeded should be something like this:

...
Install system fs image: out/target/product/armv7-a-neon/system.img

The wpa_supplicant executable from external/wpa_supplicant_8/wpa_supplicant/Android.mk will not build by default. But we can build it manually by issuing…

mmm -j8 external/wpa_supplicant_8

Also, for testing ALSA sound, build the external tinyalsa project.

mmm -j8 external/tinyalsa

Deploying Android on an SD-card

This is a very important and often times underrated step. If Android fails to boot up, it is almost always a problem of an incorrect deployment. Android needs very specific permissions and ownership for its files. For instance, the init process will fail – for security reasons – if there are any “*.rc” scripts in the root directory with incorrect file permissions. Also, other files need their user and group id’s set to shell (2000), system (1000), wifi (1010) and so on. These custom Android user and group id values are defined in system/core/include/private/android_filesystem_config.h if you are interested.

Prepare an SD-card with 3 partitions and bootloader integrated before the first partition begins, as described above in the u-boot bootloader section. The first partition will be our root file system, which is where we put both the Android root and system directory. The second partition is used as cache, and the last partition as data, both of which will be left empty.

As mentioned, it isn’t enough to simply copy the contents of the out directory to our SD card partition. We also need to modify the file permission and ownerships first, after which we could create an archive to extract to the SD-card. This could be done by hand, but luckily there are already tools available for this task, namely mktarball.sh and fs_get_stats.

Have a look at the script “export-android-sd.sh” in the updated device/generic/armv7-a-neon folder. Change the first four variables if needed, especially ANDROID_ROOT, and then execute the script. If this is the first time you run export-android-sd.sh, it will create the mentioned host tool “fs_get_stats”. The output should look something like this:

cd /opt/android/device/generic/armv7-a-neon
./export-android-sd.sh
...
...
host C: fs_get_stats <= build/tools/fs_get_stats/fs_get_stats.c
host Executable: fs_get_stats (out/host/linux-x86/obj/EXECUTABLES/fs_get_stats_intermediates/fs_get_stats)
Install: out/host/linux-x86/bin/fs_get_stats
make: Leaving directory `/opt/android/4.4.4_r1'

Now re-run the export-android-sd.sh script, which will take some time, especially for extracting the system folder.

./export-android-sd.sh
# IMPORTANT: wait for sync to complete before removing the SD-card
# alternatively, you could also use umount for safe unmounting
sync

Insert the SD-card into the Wandboard and you should be golden :)

Some useful commands for host and target

On the host:

# on the Wandboard serial terminal, issue 'su', followed by 'netcfg'
# to determine the IP address of the ethernet interface
adb connect 192.168.1.XXX
# by default, the root partition is mounted as read-only
adb shell mount -o rw,remount /
# for instance
adb push out/target/product/armv7-a-neon/symbols/system/bin/wpa_supplicant /system/bin/

On the target:

# test ALSA sound capturing and playback
# make sure to connect to the correct mic and lineout sockets
cd /data/local/tmp
tinycap test.wav
tinyplay test.wav

# restore default wpa_supplicant.conf and start wpa_supplicant service
cp /system/etc/wifi/wpa_supplicant.conf /data/misc/wifi/wpa_supplicant.conf
chmod 660 /data/misc/wifi/wpa_supplicant.conf
chown system.wifi /data/misc/wifi/wpa_supplicant.conf
start wpa_supplicant

# Enable AP mode and dnsmasq DHCP server
# Need to create a hostapd.conf file in /data/misc/wifi/hostapd.conf
# One will be created if you use the Android UI to enable AP mode.
# An example hostapd.conf with SSID=WandboardAP and PW=wandboard
# is also available in armv7-a-neon/root_overlay/hostapd.conf
ndc interface setcfg wlan0 192.168.43.1 24 up
dnsmasq --no-resolv --no-poll --pid-file --dhcp-range=192.168.43.30,192.168.43.99,1h
ndc softap startap
# to stop AP mode
ndc softap stopap

# Scan for Wifi
wpa_cli -p /data/misc/wifi/sockets/ -iwlan0
> status
> scan
> scan_results

Also, here is a compiled busybox binary for Android. Install and use with the following commands

host$ adb connect 192.168.1.XXX
host$ adb shell mount -o rw,remount /
host$ adb push busybox /system/bin
host$ adb shell
target$ busybox vi test.txt
bbb_android

Building and Deploying the Mainline (Vanilla) Android Master Source for the Beaglebone Black

Texas Instruments “AM335x” ARM platform has been gaining a lot of traction during the past couple of years. With the Beaglebone Black, a low cost board for developing on the platform is available. With the upcoming launch of the Arduino TRE which is based widely on the BBB, the platform is becoming even more interesting for the embedded industry.

In this post we would like to cover of how to get started with embedded Android development on the Beaglebone Black. While there are already excellent tutorials available of how to Build Yocto and Android Jellybean (based on the rowboat development project), this article covers building the Android Mainline (and vanilla) source code.

Continue reading

Build and deploy Yocto Linux on the Beaglebone Black

This post will show you how to build and deploy the Yocto Linux distribution on the Beaglebone Black. Since the latest Yocto 1.6 “daisy” release, there is an official board support package for the Beaglebone. Therefore, the build process will be pretty straight-forward.

Prerequisites

On an Ubuntu 12.04, you will need at least the following packages

~$ sudo apt-get install chrpath gawk diffstat texinfo g++

Download the latest Yocto release branch “daisy”

~$ mkdir yocto
~$ cd yocto
~/yocto$ git clone -b daisy git://git.yoctoproject.org/poky.git

Continue reading

Cross compiling Android’s adb and fastboot for embedded Linux (e.g. Yocto/OpenEmbedded)

The tools adb and fastboot are essential for debugging, managing and customizing Android devices. Both adb and fastboot are available for download within the ADT Bundle, however, those prebuilt binaries are for common host platforms (x86 and x86_64). What if you would like to run adb on a different architecture, such as ARM? There are of course multiple ways to get this done. Here we will show you how to cross compile adb and fastboot outside of the Android source tree using a standalone Makefile.

For this tutorial you will need

  • A cross compilation toolchain
    We will be using the official yocto project toolchain
  • Source files for adb and fastboot
    These will be in the platform/system/core and platform/system/extras repository from the official Android sources
  • Source files of three “external” projects
    Namely zlib, openssl and libselinux, which are also available from the official Android sources

Continue reading

Turn your (Linux-) Desktop / Arduino Yún / Raspberry Pi into an USB Android Accessory: How to use the Android Accessory Protocol with pyusb

py_acc

It has been a while since the post where we explained how to Turn your Linux computer into a huge Android USB Accessory. In the former post, the process of creating a C-application to communicate with your Android device has been discussed. Today, we would like to pick up on the same topic, this time however showing how communication can be established with the “pyusb” library using Python.

Since devices like the Arduino Yún or the Raspberry Pi offer a fully implemented USB stack (based on the Linux Kernel and libusb) it becomes increasingly interesting to use Python for this task.

Continue reading

Technical Blog of Nexus-Computing GmbH Switzerland