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
Installing the cross compilation toolchain
Obviously, you may skip this part if you already have a cross compiler set up. We will install an ARM cross compiler from the yocto project. Have a look at the official yocto project quick start guide if you like and then navigate to the toolchain download section. Depending on your host machine select either x86_64 or i686, and then choose the file appropriate for your target hardware. We will select poky-eglibc-x86_64-core-image-sato-armv7a-vfp-neon-toolchain-1.5.sh, since we want to run adb and fastboot on an ARM architecture later on.
Assuming it was downloaded into Downloads, execute the script
chmod a+x ~/Downloads/poky-eglibc-x86_64-core-image-sato-armv7a-vfp-neon-toolchain-1.5.sh ~/Downloads/poky-eglibc-x86_64-core-image-sato-armv7a-vfp-neon-toolchain-1.5.sh
You will be asked where you want to install the toolchain (default location is /opt/poky).
Downloading the sources
In order for the Makefile to work correctly, the core and extras repository need to be placed in a folder called system, while the three external projects need to reside within a folder called external. We will be using a relatively recent Android Kitkat version, namely android-4.4_r1.2. (You may also download the master branch by not specifying any branch at all. I have tried and compiled successfully with “android-4.4_r1.2” however.)
user@host:~$ mkdir work user@host:~$ cd work user@host:~/work$ mkdir system user@host:~/work$ cd system user@host:~/work/system$ git clone -b android-4.4_r1.2 https://android.googlesource.com/platform/system/core user@host:~/work/system$ git clone -b android-4.4_r1.2 https://android.googlesource.com/platform/system/extras user@host:~/work/system$ cd .. user@host:~/work$ mkdir external user@host:~/work$ cd external user@host:~/work/external$ git clone -b android-4.4_r1.2 https://android.googlesource.com/platform/external/zlib user@host:~/work/external$ git clone -b android-4.4_r1.2 https://android.googlesource.com/platform/external/openssl user@host:~/work/external$ git clone -b android-4.4_r1.2 https://android.googlesource.com/platform/external/libselinux
In your development folder you should now have two folders: system and external. The system folder contains two folders named core and extras; and the external folder contains the three projects zlib, openssl and libselinux.
We are going to use a custom Makefile which we copy into system/core/adb. The contents are based on an standalone Makefile for an earlier Android release from Heiher’s Blog, thanks for sharing!
# standalone Makefile for adb SRCS+= adb.c SRCS+= fdevent.c SRCS+= adb_client.c SRCS+= commandline.c SRCS+= console.c SRCS+= file_sync_client.c SRCS+= get_my_path_linux.c SRCS+= services.c SRCS+= sockets.c SRCS+= transport.c SRCS+= transport_local.c SRCS+= transport_usb.c SRCS+= usb_linux.c SRCS+= usb_vendors.c SRCS+= adb_auth_host.c VPATH+= ../libcutils SRCS+= list.c SRCS+= socket_inaddr_any_server.c SRCS+= socket_local_client.c SRCS+= socket_local_server.c SRCS+= socket_loopback_client.c SRCS+= socket_loopback_server.c SRCS+= socket_network_client.c SRCS+= load_file.c VPATH+= ../libzipfile SRCS+= centraldir.c SRCS+= zipfile.c VPATH+= ../../../external/zlib/src SRCS+= adler32.c SRCS+= compress.c SRCS+= crc32.c SRCS+= deflate.c SRCS+= infback.c SRCS+= inffast.c SRCS+= inflate.c SRCS+= inftrees.c SRCS+= trees.c SRCS+= uncompr.c SRCS+= zutil.c CPPFLAGS+= -DADB_HOST=1 CPPFLAGS+= -DHAVE_FORKEXEC=1 CPPFLAGS+= -DHAVE_SYMLINKS CPPFLAGS+= -DHAVE_TERMIO_H CPPFLAGS+= -DHAVE_SYS_SOCKET_H CPPFLAGS+= -D_GNU_SOURCE CPPFLAGS+= -D_XOPEN_SOURCE CPPFLAGS+= -I. CPPFLAGS+= -I../include CPPFLAGS+= -I../../../external/zlib CPPFLAGS+= -I../../../external/openssl/include CFLAGS+= -O2 -g -Wall -Wno-unused-parameter LIBS= -lcrypto -lpthread -lrt TOOLCHAIN= /opt/poky/1.5/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi- CC= $(TOOLCHAIN)gcc LD= $(TOOLCHAIN)gcc OBJS= $(SRCS:.c=.o) all: adb adb: $(OBJS) $(LD) -o $@ $(LDFLAGS) $(OBJS) $(LIBS) clean: rm -rf $(OBJS)
Change the TOOLCHAIN variable to your own cross compiler in case you are not using the yocto toolchain from the previous step. Now simply type make within the system/core/adb directory and you should end up with an ARM executable named adb. If you get an error similar to “Makefile:69: *** missing separator. Stop.”, then most likely the tab-indentations have been converted into white spaces on said lines. You can also check which shared libraries are needed on your target with the objdump tool.
$ vim Makefile $ make $ file adb adb: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, BuildID[sha1]=0x6c31475e9105d3f378a985e6177cafde5f3228ea, not stripped $ objdump -x adb | grep NEEDED NEEDED libcrypto.so.1.0.0 NEEDED libpthread.so.0 NEEDED librt.so.1 NEEDED libc.so.6
For compiling fastboot we will use a different Makefile inside system/core/fastboot with the following contents:
# standalone Makefile for fastboot SRCS+= protocol.c SRCS+= engine.c SRCS+= bootimg.c SRCS+= fastboot.c SRCS+= usb_linux.c SRCS+= util_linux.c VPATH+= ../../../external/zlib/src SRCS+= adler32.c SRCS+= compress.c SRCS+= crc32.c SRCS+= deflate.c SRCS+= gzclose.c SRCS+= gzlib.c SRCS+= gzread.c SRCS+= gzwrite.c SRCS+= infback.c SRCS+= inflate.c SRCS+= inftrees.c SRCS+= inffast.c SRCS+= trees.c SRCS+= uncompr.c SRCS+= zutil.c VPATH+= ../../extras/ext4_utils SRCS+= make_ext4fs.c SRCS+= ext4fixup.c SRCS+= ext4_utils.c SRCS+= allocate.c SRCS+= contents.c SRCS+= extent.c SRCS+= indirect.c SRCS+= uuid.c SRCS+= sha1.c SRCS+= wipe.c SRCS+= crc16.c VPATH+= ../../../external/libselinux/src SRCS+= booleans.c SRCS+= canonicalize_context.c SRCS+= disable.c SRCS+= enabled.c SRCS+= fgetfilecon.c SRCS+= fsetfilecon.c SRCS+= getenforce.c SRCS+= getfilecon.c SRCS+= getpeercon.c SRCS+= lgetfilecon.c SRCS+= load_policy.c SRCS+= lsetfilecon.c SRCS+= policyvers.c SRCS+= procattr.c SRCS+= setenforce.c SRCS+= setfilecon.c SRCS+= context.c SRCS+= mapping.c SRCS+= stringrep.c SRCS+= compute_create.c SRCS+= compute_av.c SRCS+= avc.c SRCS+= avc_internal.c SRCS+= avc_sidtab.c SRCS+= get_initial_context.c SRCS+= checkAccess.c SRCS+= sestatus.c SRCS+= deny_unknown.c SRCS+= callbacks.c SRCS+= check_context.c SRCS+= freecon.c SRCS+= init.c SRCS+= label.c SRCS+= label_file.c SRCS+= label_android_property.c VPATH+= ../libsparse SRCS+= backed_block.c SRCS+= output_file.c SRCS+= sparse.c SRCS+= sparse_crc32.c SRCS+= sparse_err.c SRCS+= sparse_read.c VPATH+= ../libcutils SRCS+= list.c SRCS+= socket_inaddr_any_server.c SRCS+= socket_local_client.c SRCS+= socket_local_server.c SRCS+= socket_loopback_client.c SRCS+= socket_loopback_server.c SRCS+= socket_network_client.c SRCS+= load_file.c VPATH+= ../libzipfile SRCS+= centraldir.c SRCS+= zipfile.c CPPFLAGS+= -DHOST CPPFLAGS+= -DADB_HOST=1 CPPFLAGS+= -DHAVE_FORKEXEC=1 CPPFLAGS+= -DHAVE_SYMLINKS CPPFLAGS+= -DHAVE_TERMIO_H CPPFLAGS+= -DHAVE_SYS_SOCKET_H CPPFLAGS+= -D_GNU_SOURCE CPPFLAGS+= -D_XOPEN_SOURCE CPPFLAGS+= -I. CPPFLAGS+= -I../include CPPFLAGS+= -I../mkbootimg CPPFLAGS+= -I../libsparse/include CPPFLAGS+= -I../../extras/ext4_utils CPPFLAGS+= -I../../../external/zlib CPPFLAGS+= -I../../../external/openssl/include CPPFLAGS+= -I../../../external/libselinux/include CFLAGS+= -O2 -g -Wall -Wno-unused-parameter TOOLCHAIN= /home/rudi/dev/fsl-community-bsp/build/tmp/sysroots/x86_64-linux/usr/bin/cortexa9hf-vfp-neon-poky-linux-gnueabi/arm-poky-linux-gnueabi- CC= $(TOOLCHAIN)gcc LD= $(TOOLCHAIN)gcc OBJS= $(SRCS:.c=.o) all: fastboot fastboot: $(OBJS) $(LD) -o $@ $(LDFLAGS) $(OBJS) $(LIBS) clean: rm -rf $(OBJS)
Again, simply type make and you should be all set! You can now use adb and fastboot on a Wandboard or Raspberry Pi for instance 🙂 Have a look at Getting started with Yocto on Wandboard or 12MB Minimal Image for Raspberry Pi using the Yocto Project to get started.
If you are interested in how to create the above Makefiles, have a look at the Android.mk file within the same folder. Each Makefile basically reproduces the section between include $(CLEAR_VARS) and include $(BUILD_HOST_EXECUTABLE).
Update 18.09.2014: here is also a Makefile to build adb without libcrypto dependencies (tested with Yocto on a Wandboard)