在 android 上使用 adb client

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 下生成 includelib ,包含了供我们使用的头文件和静态库。

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 下生成 includelib ,包含了供我们使用的头文件和静态库。

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
相关推荐
宏基骑士3 小时前
mac 电脑上安装adb命令
macos·adb
水瓶丫头站住4 小时前
安卓APP如何适配不同的手机分辨率
android·智能手机
xvch4 小时前
Kotlin 2.1.0 入门教程(五)
android·kotlin
xvch8 小时前
Kotlin 2.1.0 入门教程(七)
android·kotlin
望风的懒蜗牛8 小时前
编译Android平台使用的FFmpeg库
android
浩宇软件开发9 小时前
Android开发,待办事项提醒App的设计与实现(个人中心页)
android·android studio·android开发
ac-er88889 小时前
Yii框架中的多语言支持:如何实现国际化
android·开发语言·php
苏金标10 小时前
The maximum compatible Gradle JVM version is 17.
android
zhangphil10 小时前
Android BitmapShader简洁实现马赛克,Kotlin(一)
android·kotlin
Deutsch.14 小时前
MySQL——主从同步
mysql·adb