• 在 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. 下载源码

    参考上面的链接,直接使用经过版本验证源码。

    git clone https://gitee.com/jackackcheng/android-tools-4.2.2
    
    • 1

    由于平台架构是aarch64的android11,因此一般的工具链可能用不了。下载 android-ndk-r25c ,里面包含有 aarch64-linux-android30-clang 工具链,位于 android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/

    添加临时环境变量:

    export PATH=$PATH:$path/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/
    
    • 1

    可以编译个简单的helloworld,放到android上看看能不能运行,测试工具链是否可用。

    2. 编译zlib

    解压 zlib-1.2.11.tar.gz :

    tar -xzvf zlib-1.2.11.tar.gz
    
    • 1

    配置编译环境:

    ./configure --prefix=$(pwd)/../libz --static
    
    • 1

    由于 clang 编译器和 gcc 编译器的命令规则不一样,因此直接上面配置环境时指定工具链会有问题。

    因此,在配置好环境后,通过直接修改Makefile来解决这个问题。执行上述命令后,目录下会生成 Makefile。打开Makefile,修改其中和工具链相关的配置:

    CC=aarch64-linux-android30-clang
    LDSHARED=aarch64-linux-android30-clang
    CPP=aarch64-linux-android30-clang++
    AR=llvm-ar
    RANLIB=llvm-ranlib
    
    • 1
    • 2
    • 3
    • 4
    • 5

    每次执行 ./configure ,都会导致Makefile的重新生成。可以在修改后,对Makefile做个备份。

    编译:

    make -j20 
    make install -j20
    
    • 1
    • 2

    在这里插入图片描述

    安装后,会在上层目录 libz 下生成 includelib ,包含了供我们使用的头文件和静态库。

    3. 编译openssl

    和编译zlib一样,先配置好环境,然后修改 Makefile,指定 aarch64-linux-android30-clang 作为工具链。

    解压 openssl-1.0.0e.tar.gz:

    tar -xzvf openssl-1.0.0e.tar.gz
    
    • 1

    配置编译环境:

    ./Configure static os/compiler:aarch64-linux-android30-clang --prefix=$(pwd)/../libopenssl
    
    • 1

    修改Makefile:

    CC= aarch64-linux-android30-clang
    AR= llvm-ar $(ARFLAGS) r
    RANLIB= llvm-ranlib
    NM= llvm-nm
    
    • 1
    • 2
    • 3
    • 4

    编译:

    make -j20
    make install 
    
    • 1
    • 2

    在这里插入图片描述

    在这里插入图片描述

    安装后,会在上层目录 libopenssl 下生成 includelib ,包含了供我们使用的头文件和静态库。

    4. 编译adb

    进入到 android-tools-4.2.2/core/adb 目录下,里面已经由写好的 Makefile了,只需要修改工具链即可。这里我们使用静态链接,方便直接拷贝adb进行使用,避免环境问题。

    修改Makefile,指定编译生成的 zlib 和 openssl 的头文件路径和静态库文件路径:

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    编译:

    make -j20
    
    • 1

    在这里插入图片描述

    不出意外,目录下会生成 adb ,这个上传到 android 上,就可以用了。

    5. 使用问题

    通过上述流程编译的 adb,在 android 上运行是没有问题了。但是确无法识别设备,需要解决一些bug才行。

    下面是遇到的问题和解决办法。

    5.1 无法启动 server

    / # adb devices
    * daemon not running. starting it now on port 5040 *
    * daemon started successfully *
    ** daemon still not running
    error: cannot connect to daemon
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这个问题,在交叉编译到 aarch64 的 Linux上时,不会出现。

    如果 $HOME 目录下面有 .android/adb_usb.ini 文件,会从这个文件中读取 usb vendor id。

        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;
                    }
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    这里 errno 在 main 函数进入时,就已经是 Invalid argument 状态了,因此在这里会导致程序退出。暂不清楚是什么原因导致的 errno 是错误状态。因此,在 main 最开始的地方, 把 errno 置 0即可。

    int main(int argc, char **argv)
    {
        errno = 0;
    #if ADB_HOST
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.2 ADB server didn’t ACK

    / # 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    和上述原因一样,是由于errno问题意外退出导致的。adb 会默认先fork一个进程,运行 adb server,然后通过管道读取输出信息,读取到 “OK\n” 后,才会往下执行。在读取 OK 的位置添加读取信息并打印,发现读取到的是如下内容:

    temp: Invalid content in adb_usb.ini.
    temp: Quitting.
    
    • 1
    • 2

    fork 的 子进程启动 server 时,遇到 5.1 无法启动 server 的问题,退出并打印上述错误信息,然后被父进程读到。

    5.3 无法识别到device

    默认adb只识别支持的 usb vendor id 列表的设备。如果设备不在支持列表,那么是无法识别的。需要添加 device 的 usb vendor id 到 usb_vendor.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,
        ....
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    或者 创建 $HOME/.android/adb_usb.ini 文件,将需要识别设备的 usb vendor id写入到这个文件中:

    echo 0x2c7c > $HOME/.android/adb_usb.ini
    
    • 1
    / # adb devices
    List of devices attached
    f9618ed6        device
    emulator-5554   device
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    【selenium】三大切换 iframe 弹窗alert 句柄window 和 鼠标操作
    vue_router__WEBPACK_IMPORTED_MODULE_7__.default.push is not a function 错误的解决
    CSS层级小技巧:在滚动时自动添加头部阴影
    Pytorch中关于forward函数的理解与用法
    Leetcode85. 最大矩形
    python 之f-strings 来格式化字符串
    vue使用postcss-pxtorem实现自适应
    Java 实现统计文件字符
    U盘资料损坏 在线调取资料帮大忙
    超详细的JUnit单元测试介绍
  • 原文地址:https://blog.csdn.net/duapple/article/details/133041299