ADB移植和使用参考


1. 移植

ADB(Android Debug Bridge)是一种主要用于与嵌入式Linux设备进行通信和调试的命令行工具,提供了与设备之间的连接、文件传输、调试和执行命令等功能,可以通过USB连接或网络与嵌入式设备建立通信。

ADB工具编译时依赖于OpenSSL、Zlib,编译ADB工具之前需要交叉编译OpenSSL和Zlib,版本如下:

  • OpenSSL: 1.1.1i
  • Zlib: 1.2.12

1.1. 传统方式

1.1.1. OpenSSL交叉编译

OpenSSL是一个开源的软件库,提供了一组用于安全通信的密码学功能和工具,广泛用于安全协议的实现、加密通信的建立以及数字证书的管理。

1.1.1.1. 源码下载

OpenSSL下载地址

版本:1.1.1i

1.1.1.2. 交叉编译

资源包下载完成后,解压进入opensl-1.1.1i目录,执行Configure配置文件配置编译工具链和指定相应的安装路径,如下:

tar -zxvf openssl-1.1.1i.tar.gz
cd openssl-1.1.1i/
export PATH=/tools/toolchain/gcc-10.2.1-20210303-sigmastar-glibc-x86_64_aarch64-linux-gnu/bin:$PATH ; export ARCH=arm64 ; export CROSS_COMPILE=aarch64-linux-gnu-
./Configure --prefix=$PWD/install linux-aarch64
make clean -j8
make -j8
make install

注意上述示例步骤中的export命令指定的编译链地址,实际操作时请根据真实的编译链路径进行声明。执行上述步骤后将在openssl-1.1.1i/install/路径下找到生成的头文件和库文件。

1.1.2. Zlib交叉编译

Zlib是一个开源的数据压缩库,提供了高效的压缩和解压功能。

1.1.2.1. 源码下载

Zlib下载地址

版本:1.2.12

1.1.2.2. 交叉编译

资源包下载完成后,解压进入zlib-1.2.12目录,执行configure文件配置安装目录,如下:

tar -xvf zlib-1.2.12.tar.xz
cd zlib-1.2.12/
export PATH=/tools/toolchain/gcc-10.2.1-20210303-sigmastar-glibc-x86_64_aarch64-linux-gnu/bin:$PATH ; export ARCH=arm64 ; export CROSS_COMPILE=aarch64-linux-gnu-
./configure --prefix=$PWD/install/ --shared

生成Makefile后需要重新指定编译链参数:

-CC=gcc
+CC=aarch64-linux-gnu-gcc
...
-LDSHARED=gcc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map
-CPP=aarch64-linux-gnu-gcc -E
+LDSHARED=gcc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map
+CPP=aarch64-linux-gnu-gcc -E
...
-AR=ar
+AR=aarch64-linux-gnu-ar
....
-RANLIB=ranlib
+RANLIB=aarch64-linux-gnu-ranlib

修改Makefile后进行交叉编译:

make clean -j8
make -j8
make install

注意上述示例步骤中的export命令指定的编译链地址,实际操作时请根据真实的编译链路径进行声明。执行上述步骤后将在zlib-1.2.12/install/路径下找到生成的头文件和库文件。

1.1.3. ADB交叉编译

1.1.3.1. 源码下载

git clone https://github.com/yoannsculo/adbd.git

1.1.3.2. 交叉编译

下载完成后进入到adbd/adb目录下修改adb.h和Makefile。

修改adb.h如下:

-#define  ADB_TRACE    1
+#define  ADB_TRACE    0

修改Makefile(可直接覆盖):

# adbd

TOOLCHAIN=aarch64-linux-gnu-

SRCS+=adb.c
SRCS+=fdevent.c
SRCS+=transport.c
SRCS+=transport_local.c
SRCS+=transport_usb.c
SRCS+=sockets.c
SRCS+=services.c
SRCS+=file_sync_service.c
SRCS+=jdwp_service.c
SRCS+=framebuffer_service.c
SRCS+=remount_service.c
SRCS+=usb_linux_client.c
SRCS+=log_service.c
SRCS+=utils.c

VPATH+= ../libcutils
SRCS+= $(VPATH)/array.c
SRCS+= $(VPATH)/hashmap.c
SRCS+= $(VPATH)/properties.c
SRCS+= $(VPATH)/threads.c
SRCS+= $(VPATH)/socket_inaddr_any_server.c
SRCS+= $(VPATH)/socket_local_client.c
SRCS+= $(VPATH)/socket_local_server.c
SRCS+= $(VPATH)/socket_loopback_client.c
SRCS+= $(VPATH)/socket_loopback_server.c
SRCS+= $(VPATH)/socket_network_client.c
SRCS+= $(VPATH)/load_file.c

CPPFLAGS+= -DADB_HOST=0
CPPFLAGS+= -DHAVE_PTHREADS
CPPFLAGS+= -D_XOPEN_SOURCE -D_GNU_SOURCE
CPPFLAGS+= -fPIC
CPPFLAGS+= -I .
CPPFLAGS+= -I ../include
CPPFLAGS+= -I ../../zlib-1.2.12/install/include/
CPPFLAGS+= -I ../../openssl-1.1.1i/install/include/openssl/

CPPFLAGS+= -L ../../zlib-1.2.12/install/lib/
CPPFLAGS+= -L ../../openssl-1.1.1i/install/lib/

CFLAGS+= -O2 -g -Wall -Wno-unused-parameter
LDFLAGS= -static

LIBS= -lrt -lpthread -lcrypto -ldl

CC=$(TOOLCHAIN)gcc
LD=$(TOOLCHAIN)gcc
STRIP=$(TOOLCHAIN)strip

OBJS= $(SRCS:.c=.o)

all: adbd

adbd: $(OBJS)
    $(LD) -o $@ $(LDFLAGS) $(OBJS) $(LIBS) $(CPPFLAGS)
    $(STRIP) adbd

clean:
    rm -rf $(OBJS)

修改完成后进行交叉编译:

cd adbd/adb/
export PATH=/tools/toolchain/gcc-10.2.1-20210303-sigmastar-glibc-x86_64_aarch64-linux-gnu/bin:$PATH ; export ARCH=arm64 ; export CROSS_COMPILE=aarch64-linux-gnu-
make clean -j8
make all -j8

执行完将在该目录下生成adb device端应用程序adbd。

注意,上述步骤生成的adbd将依赖动态库libz.so.1。

1.2. 基于Buildroot

adb属于android-tools包,版本为4.2.2,需要确保Buildroot启用如下的配置:

BR2_PACKAGE_ANDROID_TOOLS=y
...
BR2_PACKAGE_ANDROID_TOOLS_ADB=y
BR2_PACKAGE_ANDROID_TOOLS_ADBD=y

在编译构建android-tool时,将会判断BR2_PACKAGE_ANDROID_TOOLS_ADB和BR2_PACKAGE_ANDROID_TOOLS_ADBD是否为y来决定是否编译adb和adbd。

export PATH=/tools/toolchain/gcc-10.2.1-20210303-sigmastar-glibc-x86_64_aarch64-linux-gnu/bin:$PATH ; export ARCH=arm64 ; export CROSS_COMPILE=aarch64-linux-gnu-
cd 3rdparty/buildroot-masters
make android-tools

通过该方式构建出来的adbd依赖libz.so.1、libcrypto.so.1.1、libcrypt.so.1、libatomic.so.1,相关lib库集成在3rdparty/buildroot-master/output/target/usr/lib/文件夹下。


2. 环境搭建

2.1. 内核配置

ADB的实现依赖于FunctionFS框架,因此需要打开相关的配置编译生成相应的ko,内核使用ConfigFs进行实现,打开配置如下:

Device Drivers  --->
    [*] USB support  --->
        <M>   USB Gadget Support  --->
            USB Peripheral Controller  --->
                <M> Sstar MSB250X USB 2.0 Device Controller
            ...
            <M>   USB Gadget functions configurable through configfs
                [*]   Function filesystem (FunctionFS)

最终生成列表:

udc-core.ko
libcomposite.ko
usb_f_fs.ko
udc-msb250x.ko

2.2. 镜像打包

把交叉编译生成的程序放到project\release\chip\pcupid\dispcam\common\glibc\10.2.1\release\bin\debug目录下,同时需要在应用层增加一个执行脚本才能使能Function File System,脚本内容如下:

#!/bin/sh
export LD_LIBRARY_PATH=/config/lib:$LD_LIBRARY_PATH
ifconfig lo up

USB_DEVICE_DIR=/sys/kernel/config/usb_gadget/s-star/
USB_CONFIGS_DIR=/sys/kernel/config/usb_gadget/s-star/configs/default.1
USB_FUNCTIONS_DIR=/sys/kernel/config/usb_gadget/s-star/functions

config_adb()
{
    #no attributes, all parameters are set through FunctioFS
    mkdir ${USB_FUNCTIONS_DIR}/ffs.adb
    ln -s ${USB_FUNCTIONS_DIR}/ffs.adb ${USB_CONFIGS_DIR}/ffs.adb
}

# main
if [ -d /sys/kernel/config/usb_gadget ]
then
    umount /sys/kernel/config
fi

mount -t configfs none /sys/kernel/config
mkdir $USB_DEVICE_DIR
mkdir $USB_CONFIGS_DIR
mkdir ${USB_DEVICE_DIR}/strings/0x409
mkdir ${USB_CONFIGS_DIR}/strings/0x409

# 配置configs
# MaxPower/bmAttributes
echo 0x02 > ${USB_CONFIGS_DIR}/MaxPower
echo 0xC0 > ${USB_CONFIGS_DIR}/bmAttributes

# 配置strings
# manufacturer/product/serialnumber/configuration
echo "Linux Foundation" > ${USB_DEVICE_DIR}/strings/0x409/manufacturer
echo "ADB gadget" > ${USB_DEVICE_DIR}/strings/0x409/product
echo "0123" > ${USB_DEVICE_DIR}/strings/0x409/serialnumber
echo "ADB" > ${USB_CONFIGS_DIR}/strings/0x409/configuration

# 配置function
config_adb

# 挂载并运行adbd应用
mkdir -p /dev/usb-ffs/adb
mount -o uid=2000,gid=2000 -t functionfs adb /dev/usb-ffs/adb
export TERMINFO=/config/terminfo
start-stop-daemon --start --quiet --background --exec /customer/adbd
#/customer/adbd &
#/usr/sbin/adbd &
sleep 2

# 配置device
# UDC/bDeviceClass/bDeviceProtocol/bDeviceSubClass/bMaxPacketSize0/bcdDevice/bcdUSB/idProduct/idVendor
echo 0xef > ${USB_DEVICE_DIR}/bDeviceClass
echo 0x01 > ${USB_DEVICE_DIR}/bDeviceProtocol
echo 0x02 > ${USB_DEVICE_DIR}/bDeviceSubClass
echo 0x00 > ${USB_DEVICE_DIR}/bMaxPacketSize0
echo 0x0419 > ${USB_DEVICE_DIR}/bcdDevice
echo 0x0200 > ${USB_DEVICE_DIR}/bcdUSB
echo 0x0102 > ${USB_DEVICE_DIR}/idProduct
echo 0x1d6b > ${USB_DEVICE_DIR}/idVendor
UDC=`ls /sys/class/udc/ | awk 'NR==1'`
echo $UDC > ${USB_DEVICE_DIR}/UDC

脚本默认的LD_LIBRARY_PATH指定为/config/lib,因此依赖的动态库需要导入这个路径,请根据实际需要调整。

公版默认使用USB P0口作为Device,USB P1口作为Host。若需要使用USB P1口验证,则需要修改内核DTS和脚本:

修改内核DTS如下:

        ...
        msb250x-udc-p1 {
            ...
-            status = "disabled";
+            status = "okay";
        };
        ...
        sstar_ehci1: sstar-ehci-1 {
            ...
-            status = "okay";
+            status = "disabled";
        };
        ...

修改脚本如下:

-UDC=`ls /sys/class/udc/ | awk 'NR==1'`
+UDC=`ls /sys/class/udc/ | awk 'NR==2'`

3. 测试验证

Windows host端工具:

platform-tools_r33.0.1-windows.zip

pc上环境安装完成之后,通过usb线将设备与pc端连接起来;通过以下的常用命令可以进行测试:

adb devices  --> 枚举adb设备
adb shell   --> 连接adb设备的shell
adb push/pull  -->  与adb设备进行文件传输

3.1. adb devices

3.2. adb push

3.3. adb pull

3.4. adb shell


4. 常见Q&A

Q1:adb (1.0.31 adb client)连接不上设备,要怎么解决?

PC端adb host扫描设备和连接设备时会先获取USB设备VID值,然后与已向usb if申请VID的公司或读取/user/xx/.android/adb_usb.Ini下的VID做匹配,匹配到VID, interfaceClass, interfaceSubClass, interfaceProtocol正确时,说明外接USB设备为ADB gadget,这时候才能正常连接上。

修改方法:若VID没有在已经申请的数组里,可以在个人PC电脑下创建/user/xx/.android/adb_usb.Ini文件并添加相应的VID;设备VID的查询方法在设备管理器中硬件ID中查看;

Q2:板端ADB在Windows 10上正常,但在Windows 7系统下无法识别设备该怎么处理?

这种情况一般是驱动安装的问题,可以使用这个驱动安装工具ADBDriverInstaller.zip 。在板端USB插入PC后,使用该工具查找到直接安装即可。

ADBDriverInstaller.zip

Q3:板端ADB运行后出现错误日志 error: Address family not supported by protocol: cannot open transport registration socketpair

内核配置需要开启:

makefile -*- Networking support ---> Networking options ---> <*> Unix domain sockets

Q4:板端ADB运行后出现cannot bind 'tcp:5037'

若未对adb源码进行过定制化改造,默认adb会使用到网络相关的操作,可以在板端通过ifconfig lo up避免此log出现,即让adb绑定本地回环的ip端口。

!!! note "Q5:PC端adb connect 设备IP后出现无法连接,需要对adb源码进行定制化改造,进入到adbd/adb目录下修改adb.c

    //    property_get("service.adb.tcp.port", value, "");
    //if (!value[0]) {
        //property_get("persist.adb.tcp.port", value, "");
    //}
    //if (sscanf(value, "%d", &port) == 1 && port > 0) {
    //    printf("using port=%d\n", port);
    //    listen on TCP port specified by service.adb.tcp.port property
    //    local_init(port);
    //} else
    //    printf("using port=%d\n", port);
    //    listen on TCP port specified by service.adb.tcp.port property
    //    local_init(port);
    //}
    +    char * env_port = getenv("ADB_TCP_PORT");
    +    if(!env_port){
    +        port = 5555;
    +    }else{
    +       sscanf(env_port, "%d", &port);
    +    }
    +    if(port > 0){
    +       printf("using port=%d\n", port);
    +       local_init(port);
    +    }