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. 源码下载¶
版本: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. 源码下载¶
版本: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后,使用该工具查找到直接安装即可。
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);
+ }