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

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.

Building

adb

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

fastboot

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)

11 Replies to “Cross compiling Android’s adb and fastboot for embedded Linux (e.g. Yocto/OpenEmbedded)”

  1. really helpful,
    but can we use static link in lib crypto pthread and rt,
    like
    LDFLAGS= -static
    LIBS= -lcrypto -lpthread -lrt
    I have tried,and warning not find these libs, hope we can build non-dependent adb bin file.

    1. Hi Henry,

      a while back we created a Makefile without libcrypto dependencies. However, this still needs librt and libpthread dynamically. I have put this file at the end of the post, maybe you can try to extend it. Please tell me if you succeed so we can update the above instructions.

      Best Regards
      andreas

  2. hi Andreas,Thanks for reply.
    In fact I want to use adb (high version),in some low android device.I referenced the host-adb and device adbd,they are all static linked. So I modify the Android.mk which generate adb part like below.At last build the device adb staticly successfully.

    diff –git a/adb/Android.mk b/adb/Android.mk
    index 721b48d..7e77610 100644
    — a/adb/Android.mk
    +++ b/adb/Android.mk
    @@ -139,7 +139,7 @@ include $(BUILD_EXECUTABLE)
    ifneq ($(SDK_ONLY),true)
    include $(CLEAR_VARS)

    -LOCAL_LDLIBS := -lrt -ldl -lpthread
    +#LOCAL_LDLIBS := -lrt -ldl -lpthread

    LOCAL_SRC_FILES := \
    adb.c \
    @@ -172,9 +172,11 @@ LOCAL_C_INCLUDES += external/openssl/include

    LOCAL_MODULE := adb

    -LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils
    +LOCAL_FORCE_STATIC_EXECUTABLE := true
    +LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static libcutils libc
    +#LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils

    -LOCAL_SHARED_LIBRARIES := libcrypto
    +#LOCAL_SHARED_LIBRARIES := libcrypto

    include $(BUILD_EXECUTABLE)
    endif

    1. Hi Henry & Andreas :

      I have the same need for build adb staticly for arm and i had follow you and Andreas ‘s action .

      But it still warning “ld: cannot find -lcrypto -lpthread -lrt -lc ” when i add “LDFLAGS= -static” to the Makefile .

      Can you provide more detail ?

      Sincerely thanks

  3. Thanks for the detailed guide, I was thinking whether you had tried compiling adb for armv8 like in Juno development board. I would like to try compiling adb for 64bit ARM arch and so any pointers in that direction could be helpful. Thanks.

Leave a Reply

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


*