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.
As a result of being vanilla, drivers such as graphics, are not addressed and software graphics acceleration will be used for the example. While the user interface clearly lacks the needed hardware boost of the graphics chip, Texas Instruments have decided to not compile their graphics driver for Android 4.4 Kitkat (and +). Search for the term “SGX” and “AM335” on the TI forums to get an idea of the current state of the driver. Since it is closed source and there have been no notable efforts nor results of reverse engineering it, all the hope of getting hw acceleration sadly remains with the TI team.
However, even if the performance is not optimal, it is possible to configure, compile and build Android for the platform, and very simple applications are still possible to deploy and use.
For this article the following configuration is used:
OS: Ubuntu 14.04 64 bit
Android: Master (4.4.3.2.1)
Date: 18 May 2014
This article is based on resources of Robert C Nelson, which is doing an excellent job of keeping the Kernel patches for mainline AM335x and iMX6 boards up to date! Find a multitude of tutorials of how to get started with Embedded Linux on the eewiki website.
Initializing Build Environment
For deploying a functional Android the following software components are required.
The Android Source Code
The Linux Kernel Source Code
The u-boot Source Code
Similar to Embedded Linux development, the three components work together.
U-Boot: The bootloader initializes memory and loads a Kernel image as well as a device tree blog into the RAM. Depending on the configuration those files can be acquired in various ways (tftp, nfs, ext4, fat, from SD, from EMMC …). Once loaded, the Kernel will be started (in our case as uImage binary).
Kernel: For this article we are using the 3.14 Kernel provided by the git repository from Robert C Nelson. Selecting the Android drivers under the “Staging” section, is enough to get Android running. Be aware though that for using Android in a more professional environment, merging with the Android Kernel source is advised.
Android Source: At the point of this writing, the current main branch version of android is Kitkat (working branch 4.4.3.2.1). Instead of focusing on a specific version, this article points out a recipe of getting Android to run on almost any configuration.
Build Environment Setup
Start by following the environment setup steps provided by the Android source code website (here) and make sure to install some additional tools as shown below:
sudo apt-get update sudo apt-get install git-core gnupg flex bison gperf build-essential \ zip curl libc6-dev libncurses5-dev x11proto-core-dev \ libx11-dev:i386 libreadline6-dev:i386 \ libgl1-mesa-dev g++-multilib mingw32 openjdk-6-jdk tofrodos \ python-markdown libxml2-utils xsltproc zlib1g-dev:i386 \ u-boot-tools minicom lib32ncurses5-dev \ uuid-dev:i386 liblzo2-dev:i386 minicom sudo apt-get install gparted sudo apt-get install openjdk-7-jdk sudo apt-get install -f
If you happen to have troubles running the ADT Bundle on 14.04 (get errors with adb) then you need to download these additional libraries. (Thanks to http://dandar3.blogspot.ch/2014/03/android-sdk-tools-on-ubuntu-1404-beta.html)
sudo apt-get install lib32stdc++6 lib32z1
The package “minicom” is used to communicate and interact with u-boot and linux via serial command line on the BBB. Gparted is a very helpful tool for partitioning the SD-Card. The OpenJDK is newly used to compile Android – a big step forward! Installing the proprietary oracle binary is finally no longer necessary.
For building and compiling the components, create a new working directory and give yourself access permission to read/write.
# create an android directory at the root # we are on a machine with user "nx" and host "nx" nx@nx:~$ sudo mkdir /android nx@nx:~$ sudo chown nx.nx /android nx@nx:~$ cd /android nx@nx:/android$
Make sure you have enough disk space available for the next steps. Android alone will require around 25G of free disk space, a full build will take another 15G. We recommend at least having 60G of free disk space available for building Android.
Also while it is possible to use a virtual machine, performance for compiling will be significantly better when opting to go for a native Linux install.
Building on an octa-core processor will take around 40 minutes. Performance is improved by CPU power, amount and speed of memory, speed of hard drive in that order.
Pro Tip: If your system happens to be set up by somebody other than yourself, do make sure you have a swap partition available. A build will fail if the system requires swap space during the compile process without any good hints of why it crashed. If you ever happen to get segmentation faults during the compile process, check your memory, it might be defect.
Downloading Android Sources
Downloading the Android source will take a while depending on the throughput of your network connection. The 15G large source code will be downloaded in a compressed version. The source with the build version will take up around 50GB of disk space.
If you are joining our Embedded Android workshop copy the source code from the hard drive available. If you are doing this from outside the course, then issue the following commands.
# first download repo, it is the source code control tool # of android and the chrome-os project nx@nx:/android$ mkdir ~/bin nx@nx:/android$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo # now log out of your ubuntu system and back in # this is important, since the ~bin directory will # only be added to your PATH variable if it exists # during the time of your login into the system. nx@nx:~$ cd /android nx@nx:/android$ repo init -u https://android.googlesource.com/platform/manifest nx@nx:/android$ repo sync # this command will download the entire android source code # once done, you are ready to start configuring and building
Downloading the Kernel
Thanks to the patch set of Robert C Nelson, the BBB can be used with a few patches applied on the vanilla kernel. While this might not seem significant, this is an enormous advantage of the platform towards competitors. Having mainline support is in many cases a key factor in selecting hardware components for manufacturers.
# clone the kernel inside the android directory nx@nx:/android$ git clone https://github.com/beagleboard/kernel.git # now check out the 3.14 version of the kernel nx@nx:/android$ cd kernel nx@nx:/android/kernel$ git checkout origin/3.14 -b beaglebone-3.14 # next, execute the patch.sh, which will download # the vanilla kernel and check out the 3.14y branch nx@nx:/android/kernel$ ./patch.sh
Another kernel/kernel directory is now holding the sources of the Linux kernel.
Downloading U-Boot
The AM335x processor is using u-boot as its default bootloader. Another key advantage is that it can boot a vanilla variant of u-boot which is (similar to the kernel) patched in order to adjust the boot environment. Again, the patches (and also commands) have been provided by Robert C Nelson and are accessible via github.
# download the mainline u-boot nx@nx:/android$ git clone git://git.denx.de/u-boot.git nx@nx:/android$ cd u-boot nx@nx:/android/u-boot$ git checkout v2014.04 -b tmp nx@nx:/android/u-boot$ wget -c https://raw.github.com/eewiki/u-boot-patches/master/v2014.04/0001-am335x_evm-uEnv.txt-bootz-n-fixes.patch nx@nx:/android/u-boot$ patch -p1 < 0001-am335x_evm-uEnv.txt-bootz-n-fixes.patch
This closes the initialization part of the article, now it is time for configuring and building.
Building the bootloader, u-boot
Since the downloaded Android source ships with the arm toolchain, we do not require to download an additional one.
nx@nx:/android/u-boot$ export ARCH=arm # export the toolchain, use the one provided # by the Android source code nx@nx:/android/u-boot$ export CROSS_COMPILE=/android/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi- # clean and compile nx@nx:/android/u-boot$ make clean nx@nx:/android/u-boot$ make am335x_evm_config nx@nx:/android/u-boot$ make -j16
The last command will start the compile process of the bootloader.
The output files necessary for deployment are “MLO” and “u-boot.img”.
U-Boot Environment
In order to boot Android properly, place the following uEnv.txt file onto the boot partition of the SD-Card.
# these are the contents of the uEnv.txt file # placed on the first partition of the sdcard mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype} androidboot.console=ttyO0 mem=512M init=/init ip=off androidboot.hardware=bbb mmcroot=/dev/mmcblk0p2 rw mmcrootfstype=ext4 uenvcmd=if run loaduimage; then run loadfdt;run mmcbootimage;fi loaduimage=load mmc ${bootpart} ${loadaddr} ${bootdir}/${bootfile} bootfile=uImage bootdir=/boot bootpart=0:2 fdtdir=/boot mmcbootimage=echo Booting from mmc ...; run mmcargs; bootm ${loadaddr} - ${fdtaddr}
Building and Configuring the Kernel
Building and configuring the kernel is an integral part of the process. With the help of “menuconfig” configuration is done comfortably.
# change into the kernel source directory nx@nx:/android/u-boot$ cd /android/kernel/kernel # copy the beaglebone config into ".config" nx@nx:/android/kernel/kernel$ cp ../configs/beaglebone .config nx@nx:/android/kernel/kernel$ export CROSS_COMPILE=/android/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi- nx@nx:/android/kernel/kernel$ export ARCH=arm nx@nx:/android/kernel/kernel$ export LOADADDR=0x80008000 # the next command starts the kernel configuration # via menuconfig nx@nx:/android/kernel/kernel$ make menuconfig # once you are done, save and exit and start building the # kernel image as well as the device tree blob nx@nx:/android/kernel/kernel$ make -j16 uImage dtbs # the resulting files will be in the # arch/arm/boot/ directory # 1. arch/arm/boot/uImage # 2. arch/arm/boot/dts/am335x-boneblack.dtb
Since the needed Android drivers are already selected in the provided config file (configs/beaglebone), it is not necessary to reconfigure the kernel. However, to include other drivers, such as CDC-ACM for instance, you may use configure the kernel with menuconfig as described above.
The resulting uImage and am335x-boneblack.dtb need to be copied into the second partition of the SD-Card (ext4) inside the directory “/boot” as required by the $bootdir and $fdtdir property of uEnv.txt.
At this point, deployment is already possible to an SD-Card. Although no user space has been built, the kernel can already be started and output can be analyzed on the serial command line.
Deploying Kernel and U-Boot
While Android has not been built yet, this is a good moment to check if the kernel boots properly. Therefore, a first deployment step can be very helpful.
Micro SD-Card Setup
In order to deploy Android at a later stage, formating the SD-Card properly is required. Although the setup can be changed according to your needs, this simple layout will help the project to get started.
Use the gparted tool installed earlier in order to partition the micro SD-Card as provided by the image above. After partitioning, make sure to set the boot flag for the BOOT partition.
The RFS partition should be at least 200 MB while BOOT can be around 10 MB in size.
Assign the largest bulk of the SD-card to the data partition, and a size of around 100 MB to the cache.
Copy the MLO, uEnv.txt and u-boot.img onto the BOOT partition and copy the uImage and am335x-boneblack.dtb onto the RFS partition under /boot.
# u-boot deployment nx@nx:/android/$ cp u-boot/MLO /media/$USER/BOOT/ nx@nx:/android/$ cp u-boot/u-boot.img /media/$USER/BOOT/ # kernel deployment nx@nx:/android/$ sudo mkdir /media/$USER/RFS/boot nx@nx:/android/$ sudo cp kernel/kernel/arch/arm/boot/dts/am335x-boneblack.dtb /media/$USER/RFS/boot/ nx@nx:/android/$ sudo cp kernel/kernel/arch/arm/boot/uImage /media/$USER/RFS/boot/ # sync and unmount nx@nx:/android/$ sync nx@nx:/android/$ sudo umount /media/$USER/*
Make sure the internal flash of the Beaglebone is cleared (as described here).
Building and Deploying Android
The only thing missing at this point is a user space system. For this we need to configure, compile and deploy Android to the root file system of the SD-Card.
Building Android
# first change into the Android directory # then start the configuration and build process nx@nx:/android/$ source build/envsetup.sh nx@nx:/android/$ export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 nx@nx:/android/$ choosecombo 1 mini_armv7a_neon 3 nx@nx:/android/$ time make -j16 # this will take some time now
On an up to date octa-core CPU this process is taking around 40 minutes. Thanks to a change in the new version of Android, the Oracle java development kit has finally been dropped in favor of openjdk.
The root file system will be compiled into the directory out/target/product/mini_armv7a_neon/
Deploying Android
While in most configurations Android will be shipped with a ramdisk, it is also possible to place the files onto the external SD Card storage.
For this step it is important that the labels of the SD-Card are according to the section “Micro SD-Card Setup” above. (otherwise just adjust the the variables in export-android-sd.sh)
Two helper scripts will create tarballs from the output directory and extract them with the correct file mods into the SD-Card directory.
Place the export-script altogether with a modified version of mktarball.sh into your /android directory.
export-android-sd.sh
mktarball.sh
nx@nx:/android/$ source build/envsetup.sh nx@nx:/android/$ wget http://www.nexus-computing.ch/files/export-android-sd.sh nx@nx:/android/$ wget http://www.nexus-computing.ch/files/mktarball.sh nx@nx:/android/$ chmod a+x export-android-sd.sh nx@nx:/android/$ chmod a+x mktarball.sh nx@nx:/android/$ ./export-android-sd.sh # execute it twice, since the first time an additional tool will be built nx@nx:/android/$ ./export-android-sd.sh
Make sure you are executing export-android-sd.sh from within a shell that is set up with “source build/envsetup.sh”. Furthermore, make sure the SD-card is mounted and the second partition is labelled as RFS (or otherwise adjust the variables in the beginning of the script).
Deploying the Kernel
While in the last step the Android root file system has been exported, the kernel still needs to be placed in the according location on the SD-Card. For this purpose a new “boot” directory on the RFS partition will be created and two relevant files “uImage” & “am335x-boneblack.dtb” will be copied into it.
nx@nx:/android/$ sudo mkdir /media/$USER/RFS/boot nx@nx:/android/$ sudo cp kernel/kernel/arch/arm/boot/dts/am335x-boneblack.dtb /media/$USER/RFS/boot/ nx@nx:/android/$ sudo cp kernel/kernel/arch/arm/boot/uImage /media/$USER/RFS/boot/
Deploying the u-boot Bootloader
Lastly, if not already done so as shown in the previous steps, deploy the generated files for the bootloader and also download our example uEnv.txt in order to boot Android properly.
nx@nx:/android/$ cp u-boot/MLO /media/$USER/BOOT/ nx@nx:/android/$ cp u-boot/u-boot.img /media/$USER/BOOT/ # if not done so earlier, create the uEnv.txt (or download it) nx@nx:/android/$ wget http://www.nexus-computing.ch/files/uEnv.txt nx@nx:/android/$ cp uEnv.txt /media/$USER/BOOT/
The uEnv.txt file defines a small set of environment variables in order to boot Android properly with the SD-Card formatted as described above.
Booting Android
It is time to boot Android the first time on the Beaglebone Black. While not having configured any of the build files, it is expected to run into troubles the first time booting. However, at this point properly booting into the bootloader, kernel and user space successively, are very helpful to verify basic functionality of the deployment.
Make always sure to sync and umount before you remove the SD-CARD from your host system!
nx@nx:/android/$ sync nx@nx:/android/$ sudo umount /media/$USER/*
If you haven’t cleared the internal flash of the Beaglebone Black yet then make sure you follow these steps first before proceeding with this article. This step is very important, since otherwise your Angstrom distribution will boot from the internal flash.
Connect the USB-Serial (UART) Adapter with the Beaglebone Black, and start up minicom. See this excellent guide from elinux.org which explains which connectors are compatible and to which pins to hook them up.
Follow these instructions to set up minicom and connect to the serial command line of the Beaglebone. Once set up, insert the SD-Card into the Beaglebone Black and you should see an output similar to this:
U-Boot 2014.04-dirty (May 18 2014 - 21:18:08) I2C: ready DRAM: 512 MiB NAND: 0 MiB MMC: OMAP SD/MMC: 0, OMAP SD/MMC: 1 *** Warning - readenv() failed, using default environment Net: <ethaddr> not set. Validating first E-fuse MAC cpsw, usb_ether Hit any key to stop autoboot: 0 gpio: pin 53 (gpio 53) value is 1 mmc0 is current device gpio: pin 54 (gpio 54) value is 1 SD/MMC found on device 0 reading uEnv.txt 492 bytes read in 4 ms (120.1 KiB/s) gpio: pin 55 (gpio 55) value is 1 Loaded environment from uEnv.txt Importing environment from mmc ... Checking if uenvcmd is set ... gpio: pin 56 (gpio 56) value is 1 Running uenvcmd ... 3802728 bytes read in 253 ms (14.3 MiB/s) 31547 bytes read in 39 ms (789.1 KiB/s) Booting from mmc ... ## Booting kernel from Legacy Image at 82000000 ... Image Name: Linux-3.14.1+ Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 3802664 Bytes = 3.6 MiB Load Address: 80008000 Entry Point: 80008000 Verifying Checksum ... OK ## Flattened Device Tree blob at 88000000 Booting using the fdt blob at 0x88000000 Loading Kernel Image ... OK Using Device Tree in place at 88000000, end 8800ab3a Starting kernel ... ... $
Android is now booting, however, the surfaceflinger will crash, since it expects to find an opengl implementation which is not compiled yet. Also no data partition will be found nor mounted. This needs to be corrected. While for a professional setup, these files and changes should always be incorporated in the specific BoardConfig.mk and mini_common.mk .
Post Build Configuration
In order to fix this problem, a couple of files and binaries are necessary.
First, build the software opengl renderer.
nx@nx:/android/$ source build/envsetup.sh nx@nx:/android/$ export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 nx@nx:/android/$ choosecombo 1 mini_armv7a_neon 3 nx@nx:/android/$ mmm -j16 frameworks/native/opengl/libagl/ # insert the SD-Card into the host nx@nx:/android/$ sudo mkdir /media/$USER/RFS/system/lib/egl nx@nx:/android/$ sudo cp out/target/product/armv7-a-neon/system/lib/egl/libGLES_android.so /media/$USER/RFS/system/lib/egl nx@nx:/android/$ sudo chmod 644 /media/$USER/RFS/system/lib/egl/libGLES_android.so nx@nx:/android/$ sync
Next, download the fstab.bbb and init.bbb.rc and copy them to the root folder (also adjust modes).
nx@nx:/android/$ wget http://www.nexus-computing.ch/files/fstab.bbb nx@nx:/android/$ wget http://www.nexus-computing.ch/files/init.bbb.rc nx@nx:/android/$ sudo cp fstab.bbb /media/$USER/RFS/ nx@nx:/android/$ sudo cp init.bbb.rc /media/$USER/RFS/ nx@nx:/android/$ sudo chmod 644 /media/$USER/RFS/fstab.bbb nx@nx:/android/$ sudo chmod 750 /media/$USER/RFS/init.bbb.rc # dont forget to sync and umount! nx@nx:/android/$ sync nx@nx:/android/$ sudo umount /media/$USER/*
Plug your SD-Card back into the Beaglebone Black and hit the reset button.
Android will now boot and you should be able to get visuals on your HDMI screen. Congratulations, you just booted an entirely vanilla master Android / Linux configuration.
Hi
thanks for the nice tutorial…do you think it will work also on Wandboard, using Robert Nelson kernel as base?
Hey Michele,
We are actually working on something like that 🙂
Hi Michele
Regarding the Wandboard, you might be interested in this post.
cheers
andreas
Hi guys
Thanks for the wonderful post. I am trying to follow the steps and when it comes to building android, i am getting an error. I got android 4.4.4_r2 (bleeding edge) and when i build, I get:
Yacc: aidl <= frameworks/base/tools/aidl/aidl_language_y.y
prebuilts/misc/linux-x86/bison/bison -d -o out/host/linux-x86/obj/EXECUTABLES/aidl_intermediates/aidl_language_y.cpp frameworks/base/tools/aidl/aidl_language_y.y
/bin/bash: prebuilts/misc/linux-x86/bison/bison: No such file or directory
When i look at the file "prebuilts/misc/linux-x86/bison/bison", it is a 32 bit binary . So i am not sure why its picking that version when my host is a 32 bit.
Here is the environment details:
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.4.4
TARGET_PRODUCT=mini_armv7a_neon
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
HOST_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.13.0-32-generic-x86_64-with-Ubuntu-14.04-trusty
HOST_BUILD_TYPE=release
BUILD_ID=KTU84Q
OUT_DIR=out
Any help is much appreciated,
thanks!
Thank you for this excellent guide.
But at the end surfaceflinger still crashed with message “couldn’t find an OpenGL ES implementation” in log.
system/lib/egl/libGLES_android.so is compiled and copied to target.
Following all the steps including openGL, fstab.bbb, init.bbb.rc etc. Inserted the SD card into BBB. Booting reaches to a stage where small “ANDROID” is shown at the left side of the screen.
But then nothing happens beyond this point.
Please guide.
Hi Hemant,
did you resolved the issue?
if yes, please share how it has been solved.
We are struct at the same point.
thanks
mahesh
LCD screen does not work for me using this? Is this the case for anyone else?