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); + }