adb tool 分为 adb 和 adbd。 adb 用作 host 使用,包含了client和server,adbd 则作为 device 端,在 android 源码目录下,共用一套源码。但 android 源码下的 adb,不支持把 adb 编译为 android 平台的 adb client。因此需要自己进行交叉编译。
参考链接:
https://blog.csdn.net/disappears_nick/article/details/117031743
https://gitee.com/jackackcheng/android-tools-4.2.2
1. 下载源码
参考上面的链接,直接使用经过版本验证源码。
bash
git clone https://gitee.com/jackackcheng/android-tools-4.2.2
由于平台架构是aarch64的android11,因此一般的工具链可能用不了。下载 android-ndk-r25c
,里面包含有 aarch64-linux-android30-clang
工具链,位于 android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/
。
添加临时环境变量:
bash
export PATH=$PATH:$path/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/
可以编译个简单的helloworld,放到android上看看能不能运行,测试工具链是否可用。
2. 编译zlib
解压 zlib-1.2.11.tar.gz
:
bash
tar -xzvf zlib-1.2.11.tar.gz
配置编译环境:
./configure --prefix=$(pwd)/../libz --static
由于 clang 编译器和 gcc 编译器的命令规则不一样,因此直接上面配置环境时指定工具链会有问题。
因此,在配置好环境后,通过直接修改Makefile来解决这个问题。执行上述命令后,目录下会生成 Makefile。打开Makefile,修改其中和工具链相关的配置:
makefile
CC=aarch64-linux-android30-clang
LDSHARED=aarch64-linux-android30-clang
CPP=aarch64-linux-android30-clang++
AR=llvm-ar
RANLIB=llvm-ranlib
每次执行 ./configure
,都会导致Makefile的重新生成。可以在修改后,对Makefile做个备份。
编译:
bash
make -j20
make install -j20
安装后,会在上层目录 libz
下生成 include
和 lib
,包含了供我们使用的头文件和静态库。
3. 编译openssl
和编译zlib一样,先配置好环境,然后修改 Makefile,指定 aarch64-linux-android30-clang 作为工具链。
解压 openssl-1.0.0e.tar.gz
:
bash
tar -xzvf openssl-1.0.0e.tar.gz
配置编译环境:
bash
./Configure static os/compiler:aarch64-linux-android30-clang --prefix=$(pwd)/../libopenssl
修改Makefile:
makefile
CC= aarch64-linux-android30-clang
AR= llvm-ar $(ARFLAGS) r
RANLIB= llvm-ranlib
NM= llvm-nm
编译:
bash
make -j20
make install
安装后,会在上层目录 libopenssl
下生成 include
和 lib
,包含了供我们使用的头文件和静态库。
4. 编译adb
进入到 android-tools-4.2.2/core/adb
目录下,里面已经由写好的 Makefile了,只需要修改工具链即可。这里我们使用静态链接,方便直接拷贝adb进行使用,避免环境问题。
修改Makefile,指定编译生成的 zlib 和 openssl 的头文件路径和静态库文件路径:
makefile
CC:=aarch64-linux-android30-clang
CPPFLAGS+= -I/media/data1/library/tmp/2_adb/android-tools-4.2.2/libopenssl/include
CPPFLAGS+= -I/media/data1/library/tmp/2_adb/android-tools-4.2.2/libz/include
LIBS+= -lc -pthread /media/data1/library/tmp/2_adb/android-tools-4.2.2/libz/lib/libz.a /media/data1/library/tmp/2_adb/android-tools-4.2.2/libopenssl/lib/libcrypto.a
编译:
bash
make -j20
不出意外,目录下会生成 adb
,这个上传到 android 上,就可以用了。
5. 使用问题
通过上述流程编译的 adb,在 android 上运行是没有问题了。但是确无法识别设备,需要解决一些bug才行。
下面是遇到的问题和解决办法。
5.1 无法启动 server
bash
/ # adb devices
* daemon not running. starting it now on port 5040 *
* daemon started successfully *
** daemon still not running
error: cannot connect to daemon
这个问题,在交叉编译到 aarch64 的 Linux上时,不会出现。
如果 $HOME 目录下面有 .android/adb_usb.ini
文件,会从这个文件中读取 usb vendor id。
c
if (get_adb_usb_ini(temp, sizeof(temp)) == 0) {
FILE * f = fopen(temp, "rt");
if (f != NULL) {
/* The vendor id file is pretty basic. 1 vendor id per line.
Lines starting with # are comments */
while (fgets(temp, sizeof(temp), f) != NULL) {
if (temp[0] == '#')
continue;
long value = strtol(temp, NULL, 0);
printf("vendor id: 0x%lx\n", value);
if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) {
printf("errno: %s\n", strerror(errno));
fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_ADB_INI);
exit(2);
}
vendorIds[vendorIdCount++] = (int)value;
/* make sure we don't go beyond the array */
if (vendorIdCount == VENDOR_COUNT_MAX) {
break;
}
}
}
}
这里 errno 在 main 函数进入时,就已经是 Invalid argument
状态了,因此在这里会导致程序退出。暂不清楚是什么原因导致的 errno 是错误状态。因此,在 main 最开始的地方, 把 errno 置 0即可。
c
int main(int argc, char **argv)
{
errno = 0;
#if ADB_HOST
}
5.2 ADB server didn't ACK
bash
/ # adb devices
service: host:devices
* daemon not running. starting it now on port 5040 *
ADB server didn't ACK
* failed to start daemon *
error: cannot connect to daemon
和上述原因一样,是由于errno问题意外退出导致的。adb 会默认先fork一个进程,运行 adb server,然后通过管道读取输出信息,读取到 "OK\n" 后,才会往下执行。在读取 OK 的位置添加读取信息并打印,发现读取到的是如下内容:
bash
temp: Invalid content in adb_usb.ini.
temp: Quitting.
fork 的 子进程启动 server 时,遇到 5.1 无法启动 server 的问题,退出并打印上述错误信息,然后被父进程读到。
5.3 无法识别到device
默认adb只识别支持的 usb vendor id 列表的设备。如果设备不在支持列表,那么是无法识别的。需要添加 device 的 usb vendor id 到 usb_vendor.c
中:
c
/** built-in vendor list */
int builtInVendorIds[] = {
VENDOR_ID_GOOGLE,
VENDOR_ID_INTEL,
VENDOR_ID_HTC,
VENDOR_ID_SAMSUNG,
VENDOR_ID_MOTOROLA,
VENDOR_ID_LGE,
VENDOR_ID_HUAWEI,
VENDOR_ID_ACER,
VENDOR_ID_SONY_ERICSSON,
VENDOR_ID_FOXCONN,
VENDOR_ID_DELL,
VENDOR_ID_NVIDIA,
0x2c7c,
....
或者 创建 $HOME/.android/adb_usb.ini
文件,将需要识别设备的 usb vendor id写入到这个文件中:
bash
echo 0x2c7c > $HOME/.android/adb_usb.ini
/ # adb devices
List of devices attached
f9618ed6 device
emulator-5554 device