资讯动态

ARM Linux 自编译 adb:从交叉编译到稳定部署排障全攻略

发布时间:2026/10/22 14:34:27 来源:尧图企业网站定制
简介面向嵌入式 Linux 与 Android 开发者的 adb 工具源码包支持在 ARM、ARM64、x86 等架构上交叉编译生成可用的 adb 工具。包内为 adb-master 源码工程作者已在实际 ARM 机器上按 README 编译通过产物可正常使用使用者无需摸索依赖关系按文档操作即可获得适合目标平台的调试工具。该源码包能让读者直接看到 Android Debug Bridge 的主体实现在开发板联调、系统 ROM 定制、车载与物联网设备维护等场景中发挥作用也能帮助理解 adb 的编译依赖、配置选项与交叉编译流程。资源以 tgz 格式打包整体约 41.9MB上游暂未提供文件总数与类型明细这里不做无中生有解压后可通过目录结构快速定位源码、构建说明与配置脚本建议在 Linux 或类 Unix 环境下配合交叉编译器使用。已有 180 人学习/下载对有 Android 调试、嵌入式移植需求的开发者具有实际参考价值。1. 看清 arm_adb-master_default.tgz这一类包在解决什么问题拿到一个名叫arm_adb-master_default.tgz的压缩包先别急着解压命名里其实藏着关键信息arm 指目标架构master 指源码分支default 指构建配置。这类包多出自内部构建流水线是面向 ARM Linux 设备交叉编译出来的 adb 调试工具官方 SDK 的 platform-tools 从不发布 linux-arm 预编译版做开发板、盒子、工业设备调试的人只能自己编译或从内部 CI 取这种产物再手工部署。这篇笔记把拿到包之后的所有动作讲透怎么安全解包、判断 armv7 还是 arm64 并部署怎么从源码自产一个怎么排查连不上、没权限、反复 offline 的坑最后让 adb 服务稳定常驻。适合刚接触自编译 adb 的嵌入式开发者也适合正在排 ARM 设备调试链路故障的人。2. 解包与部署动手前先确认它是不是你能跑的 ARM 版本2.1 解包先看内清单tar tf 与 file 组合判断架构拿到arm_adb-master_default.tgz后我从不先解压而是先执行一次tar tzf看包内到底有几个文件。很多自编译包只塞了一个裸的 adb 二进制也有的会把lib/目录、README 甚至 udev 规则样本一起打进去。先看清单能避免后续满头找文件。tar tzf arm_adb-master_default.tgz这一步能看到完整路径。如果二进制在子目录里后续部署时别直接把整个目录拷到/usr/local/bin否则会得到一堆散落文件。看懂清单后解压到工作目录再用file确认它到底是哪个指令集的产物mkdir -p ~/arm-adb-pkg tar xzf arm_adb-master_default.tgz -C ~/arm-adb-pkg file ~/arm-adb-pkg/adbfile输出里最常出现两类结果ELF 32-bit LSB executable, ARM, EABI5对应 armv7ELF 64-bit LSB executable, ARM aarch64对应 arm64。看到 x86_64 就说明这个包根本不是给 ARM 用的趁早放下。注意有些包会做压缩壳file首行会显示statically linked或dynamically linked后者意味着后续必须检查动态库依赖。2.2 部署到目标路径install、PATH 与权限一次到位确认架构匹配后部署时不要用cp结束。cp 只拷贝文件内容不保证可执行位正确也不解决目标系统缺少目录的问题。我一般用install一步完成拷贝加权限设置再顺手检查 PATH。sudo install -m 0755 ~/arm-adb-pkg/adb /usr/local/bin/adb adb versioninstall -m 0755意思是复制文件到/usr/local/bin并保证根用户可写、所有用户可读可执行。adb version是最快的冒烟测试能打出版本号和 1.0.x 协议版本说明解释器和基本库没问题。输出类似Android Debug Bridge version 1.0.41才是正常状态。如果目标板是非 root 的嵌入式系统install装不上就退回用户目录部署再把路径加进~/.profile或~/.bashrcinstall -m 0755 ~/arm-adb-pkg/adb ~/bin/adb echo export PATH$HOME/bin:$PATH ~/.profile source ~/.profile这里有个容易忽视的细节adb在运行时会找$HOME/.android/adbkey作为设备授权私钥还要能写$HOME/.android目录。如果部署路径没问题但授权一直失败先查运行用户的 HOME 是否指向一个可写的目录。2.3 验证可执行性ldd 与 readelf 检查运行依赖ARM Linux 上的“能执行”和“能跑起来”是两件事。文件格式对了动态链接器找不到终端只会甩一句No such file or directory而且这句话连文件名都指不出来。原因是内核找不到 ELF 解释器。所以部署完adb version如果报这种错立刻用ldd查依赖ldd /usr/local/bin/adbldd会列出一串libc.so.6 /lib/arm-linux-gnueabihf/libc.so.6之类的映射。常见缺失项是libstdc.so.6、libgcc_s.so.1、libusb-1.0.so.0。瘦身过的 rootfs 经常没有 C 运行时库补装对应架构的libstdc即可libusb直接影响 USB 枚举功能缺失时adb devices会直接空列表。真正难查的是 glibc 版本偏老readelf -V /usr/local/bin/adb | grep -i GLIBC_这段会列出GLIBC_2.27、GLIBC_2.28之类的版本需求。目标板执行ldd --version看自带的 glibc 版本如果低于二进制需求报错会出现在运行时而不是加载时。遇到这种问题只有两条路换一个在更低版本 glibc 上编译的包或者走第 6 章的静态编译方案没有第三条捷径。3. 自己产出一个 arm 版 adb交叉编译最小流水线3.1 官方为什么没有 linux-arm 预编译包从构建产物命名说起很多人第一次见到arm_adb-master_default.tgz会问为什么官方不直接提供 ARM Linux 版原因是 adb 在官方构建体系里分为两个完全不同的产物跑在设备上的守护进程 adbd和跑在开发机上的客户端 adb。官方发布渠道只维护 Windows、macOS、Linux x86_64 三类客户端ARM 设备上的 adbd 则被打进系统镜像极少单独分发。于是做嵌入式的人只能自给自足。master_default这个组合是有含义的master是源码分支default是构建系统里的默认目标配置。理解了这层命名就明白这个包不是某个厂商的定制版而是“某条构建流水线用默认配置编出来的产物”拿到手必须自己验证质量。自产一个 ARM 版 adb 有三条路线在 AOSP 源码树里用 Soong 构建系统单编、用 NDK 工具链小范围手工编、直接在目标板子上用原生工具链编。第三种最稳但速度慢适合验证。前两种适合批量出包下面分别拆开。3.2 从源码树单编 adbdlunch 到 m adbd 的产物路径如果你的目标是把 adbd 集成到系统镜像里或者想获得与官方同源的构建方式AOSP 源码树单编是最可靠的路径。关键点在于 lunch 目标决定了 ARM 位宽aosp_arm64-userdebug出 64 位产物aosp_arm-userdebug出 32 位产物。userdebug 和 user 的区别直接影响第 5 章要讲的adb root权限。source build/envsetup.sh lunch aosp_arm64-userdebug m adbd构建完成后产物默认在out/target/product/generic_arm64/system/bin/adbd。如果你是 x86 主机上执行这条命令得到的 host 端adb客户端仍然是 x86_64 的因为 lunch 只切换目标系统架构不切换构建机架构。很多人在这步翻车lunch 之后以为m adb会产出 ARM 客户端实际拿到out/host/linux-x86/bin/adb才发现编错了方向。所以源码树单编最适合的场景是做系统镜像内嵌的 adbd。想拿一个能跑在 ARM Linux 发行版上的独立 adb 客户端这条路走不通要继续往下看 NDK 方式。3.3 用 NDK 工具链小范围出包命令与必调参数NDK 方式适合只想要一个二进制、不想拉整个源码树的情况。常见做法是把 adb 相关源文件从源码树里取出来连带 libbase、libcutils 等依赖头文件用 NDK 的 clang 交叉编译。命令骨架如下完整依赖列表以源码树内 Android.bp 编译单元为准export NDK/opt/android-ndk-r21e export TARGETaarch64-linux-android export API30 export TC$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin $TC/${TARGET}${API}-clang -stdc17 \ -I./include -I./libbase/include -I./libcutils/include \ adb/*.cpp adb/client/*.cpp \ -L./out -lbase -lcutils -lcrypto -lpthread \ -o adb-arm64这里几个参数必须说明白。API30决定链接哪个版本的 bionic libcAPI 太低会导致新符号缺失太高会让产物在旧系统上无法运行-lcrypto是 openssl 的加密库adbd 在做安全连接和数据传输时依赖它缺失会报一堆 undefined reference-lpthread在多线程模型下必不可少。整套命令的坑在于源文件之间的依赖关系经常超出这几个目录所以正式出包不要手工拼命令而是在源码树里写好 Android.bp 再编。NDK 编出来的产物链接的是 bionic而不是大多数 ARM Linux 发行版的 glibc。放在纯 Linux rootfs 上执行时个别系统调用行为有差异适合目标环境本来就是安卓用户态的场景。如果目标是 Debian 系 ARM 板卡更稳妥的是用aarch64-linux-gnu-g配 glibc 静态链接第 6 章详细展开。3.4 两种出包路线的选择对比路线产物场景依赖管理体积主要坑AOSP 源码树单编系统镜像内嵌 adbd随镜像分发自动解决较大host 工具仍是 x86方向易搞混NDK 手工编独立 ARM Linux 二进制需自备 libcrypto 等库较小bionic 与 glibc 行为差异板端原生编验证与调试为主完全随板子走不定速度慢工具链需现装选哪条看交付形态要进系统镜像就 AOSP 单编要独立发布、能复制到任意同架构板子上跑就 NDK 或交叉工具链手工编。arm_adb-master_default.tgz这类包名里的default暗示的就是 AOSP 默认构建配置所以它多半是第一种路线出来的拿到手先按第 2 章查依赖别假设它自带一切。4. 跑通 ARM 板上的 adb从识别到连接授权的完整链路4.1 adb devices 为空时按顺序查的三个地方部署完二进制接上 USB 设备后最常见的结果不是连接成功而是adb devices打印一行空列表。很多人在这一步开始怀疑二进制编坏了其实二进制能打印版本号就基本没问题。排查顺序要固定不要乱跳先查 USB 层再查 adb server最后查授权状态。adb kill-server adb start-server adb devices -l lsusb dmesg | tail -20adb kill-server和adb start-server是强制重置 adb server 的标准动作很多 disconnect 或 offline 状态靠这一步就能恢复。lsusb看 USB 总线是否枚举出设备如果这里都看不到目标设备问题在硬件连接或驱动层adb 层不必继续查。dmesg最后 20 行能看到 USB 设备的插拔事件出现device descriptor read/64, error -110之类的报错多半是供电不足换带屏蔽的线或加独立供电。USB 层正常但 adb 列表仍为空时重点看设备上有没有弹授权确认框。自编译 adbd 在某些固件上默认不弹框而是静默拒绝这时adb devices会显示unknown或offline优先检查 adbd 进程是否真的在跑adb shell ps -A | grep adbd在 ARM 板子上这条命令如果提示error: no devices found说明 adbd 根本没起来回到部署目录检查权限和动态库能列出adbd进程则说明 USB 枚举和 adb 传输层都通了问题只剩授权。4.2 Udev 规则与 USB 权限的最小配置嵌入式 Linux 上adb devices显示一串问号或者直接报no permissions基本是 udev 规则没写好。adb 需要访问 USB 设备节点默认权限是 root 专属普通用户必须靠 udev 规则把设备节点权限放开。最小可用规则如下echo SUBSYSTEMusb, ATTR{idVendor}18d1, MODE0666, GROUPplugdev | sudo tee /etc/udev/rules.d/51-android.rules sudo udevadm control --reload-rules sudo udevadm trigger18d1是安卓调试模式的常见 vendor ID但很多国产设备用的是自己的 ID。插上设备后执行lsusb看输出把ID xxxx:xxxx里的厂商段替换进规则否则规则永远不会命中。MODE0666表示所有用户可读写开发环境图省事可以这么写讲究一点就只开放plugdev组并把自己的账号加进组里sudo usermod -aG plugdev $USER newgrp plugdev规则加载后必须重新插拔 USB 线udevadm trigger只重新扫描设备不能替代物理重插。我在几块板子上踩过这个坑规则文件路径写错成/etc/udev/rules.d51-android.rules少了斜杠导致根本不生效排查时udevadm info /dev/bus/usb/001/003能看到匹配到了哪条规则建议每次都看一眼确认。4.3 adb tcpip 无线调试端口占用与 RSA 授权的两个隐性条件USB 口不够用或板子位置不便时无线调试是刚需。ARM 设备上启用无线调试的标准操作是 adb tcpip 模式先用 USB 连接执行adb tcpip 5555让 adbd 监听 5555 端口再拔掉线通过局域网连接。adb tcpip 5555 adb connect 192.168.1.100:5555 adb devices第一次adb connect大概率会得到unable to connect原因通常不是网络不通而是设备端没有开启对应的 TCP 监听。部分运行自定义 Linux 的板子adbd 启动参数里没有-a监听所有网络接口功能正常却只监听 USB 抽象设备这时候adb tcpip 5555不会生效需要在启动脚本里给 adbd 加-a -L tcp:5555参数。端口也被 5555 占用时换端口要同步知道设备端用的是-L tcp:你的端口两端不一致必然连不上。无线连接成功后授权环节一样不少。上位机的~/.android/adbkey.pub会被推送到设备的/data/misc/adb/adb_keys如果设备端无法写入例如只读 rootfs就会出现反复要求授权但永远unauthorized。解决方式是把上位机公钥直接追加进设备端 adb_keys 文件再重启 adbd。5. arm 版 adb 常见坑五条现象、原因、解决排障记录5.1 能执行但报错缺 libstdc.so.6动态链接的依赖没带全现象adb version输出一串error while loading shared libraries: libstdc.so.6: cannot open shared object file文件本身存在且权限正确。原因交叉编译时选择了动态链接产物依赖目标板的 C 运行时库而精简 rootfs 根本没装 libstdc。NDK 工具链编出的二进制依赖尤其隐蔽报错信息会指向一个并不存在的路径。解决优先补装目标板架构的 libstdcDebian 系用apt-get install libstdc6自研 rootfs 则从工具链目录把libstdc.so.6拷到/usr/lib。想彻底摆脱这类问题改用静态编译见第 6 章。5.2 Exec format errorarmv7 与 arm64 子架构拿错现象执行./adb直接返回cannot execute binary file: Exec format errorfile却正常打印 ELF 信息。原因包名只写了 arm没区分 armv7 还是 arm64。把 64 位产物拷到仅支持 32 位指令集的板子上内核加载器直接拒绝。arm64 内核通常能运行 32 位兼容程序反向则不行。解决在目标板执行uname -maarch64 就找 arm64 包armv7l 找 32 位包。自编译时lunch 目标aosp_arm64-userdebug和aosp_arm-userdebug必须先确认清楚别拿 CI 产物省这一步。5.3 device offlineserver 与 adbd 协议版本不一致现象adb devices能看到设备序列号但状态栏一直是offline拔插和 kill-server 都无效。原因上位机 adb server 的协议版本和设备端 adbd 的协议版本差距过大。自编译 adbd 用的源码分支是 master而上位机 platform-tools 是长期稳定版两边的加密握手和消息格式不兼容server 无法识别设备状态。解决把上位机 adb 也换成同分支产物或者反过来让设备端跑稳定分支。判断差距最简单的方式是两边分别执行adb version版本号 1.0.4x 后面的 x 代表特性版本差距超过 1 就要警惕。临时恢复通信的办法是adb kill-server后让 server 重新握手但根源不解决offline 还会复现。5.4 no permissionsudev 规则或组权限没有生效现象adb devices输出no permissions (user in plugdev group; are your udev rules wrong?)设备节点看得到但打不开。原因udev 规则没命中目标设备或规则加载后没有重新插拔。还有一种隐蔽情况设备先以充电模式枚举再切换到 adb 模式vendor ID 变了但规则只覆盖了第一种。解决执行lsusb拿到实际 vendor ID确认 udev 规则里的 ID 完全匹配重新插拔后执行udevadm test /sys/class/usb_device/...看规则匹配日志。把规则里加了ATTR{idProduct}的更麻烦同厂商不同型号会误伤建议只锁 vendor 段。5.5 adb root 被拒绝user 版固件不开放 root现象adb root返回adbd cannot run as root in production builds即使当前用户是 root、adb shell也能正常执行。原因adbd 在编译时通过 ro.secure 属性决定是否允许 root 切换。user 版固件强制 secure1adbd 收到 root 请求会主动放弃特权这是安全设计不是故障。解决开发用固件选择 userdebug 版本编镜像时lunch aosp_arm64-userdebug而不是aosp_arm64-user。已经刷了 user 版固件的板子不想重刷可以用adb shell setprop ro.secure 0临时摸一下但重启即失效且部分固件禁止修改该属性。工程上最稳的还是在编译阶段就把 debug 配置固化进镜像。6. 让这个包真正焊进开发流静态编译、服务守护与稳定性验证6.1 静态编一版免掉目标板上所有动态依赖如果arm_adb-master_default.tgz拿到手后第 2 章那一串依赖检查让你头疼最釜底抽薪的解法是出一个静态链接版本。用 glibc 交叉工具链时在编译命令里加-static产物会把 libc、libstdc、libgcc 全部打进二进制即使目标板 rootfs 里根本没有 C 库也能运行。aarch64-linux-gnu-g -static -stdc17 \ -I./include adb/*.cpp \ -L./out -lbase -lcutils -lcrypto -lpthread \ -o adb-arm64-static代价是体积明显变大常见结果是十几兆到几十兆。体积敏感的场景改用 musl 工具链做静态编译能做到体积和兼容性的平衡NDK 的 bionic 静态产物也常见但要在非安卓 rootfs 上先做一轮完整测试个别系统调用行为差异只能靠实测暴露。出包后用file确认输出里带statically linked再拷到板子上跑一次adb version。6.2 以服务方式常驻systemd 写法解决掉线重启单独执行 adb server 会随终端退出而结束板子重启后调试通道也没了。做嵌入式交付时我习惯把 adb server 交给 systemd 托管统一处理开机自启和崩溃重启[Unit] DescriptionAndroid Debug Bridge Server Afternetwork.target [Service] Typesimple ExecStart/usr/local/bin/adb -a -L tcp:5037 nodaemon server Restartalways RestartSec5 [Install] WantedBymulti-user.target-a让 adbd 监听所有网络接口适合板子需要被局域网设备访问的场景-L tcp:5037把服务端口定死避免运行时被其他进程抢占nodaemon server表示以前台方式运行systemd 能直接管理它的生命周期。不习惯 systemd 的旧板子可以退回到/etc/inittab里加一行 respawn 条目效果类似。服务写好后systemctl enable adb-server设为开机自启并用systemctl status adb-server确认没有进入 restart 死循环。6.3 出包前的稳定性验证脚本交付自编译 adb 之前别只测一次adb version就发出去。调试工具的稳定性要靠压力验证尤其无线模式和反复插拔场景。下面这段脚本可以放到 CI 的最后一个阶段循环重连并记录失败次数for i in $(seq 1 100); do timeout 20 adb wait-for-device || echo round $i: device timeout adb connect 192.168.1.100:5555 /dev/null adb -s 192.168.1.100:5555 shell uptime /dev/null || echo round $i: shell failed sleep 3 donetimeout 20防止 wait-for-device 永久阻塞shell uptime验证的不只是设备存在而是 adbd 能真正处理指令这个才是调试链路的完整通路。100 轮里出现 1 到 2 次失败先看是不是网络抖动失败率超过 5%基本可以判定是二进制或服务配置的问题进第 5 章逐条对照。这类验证跑过一次后面调参数就有底气不用靠运气赌连接。我自己在这个方向上交过不少学费最贵的一条教训是拿了 CI 产物不验证依赖就直接刷进镜像结果现场所有板子无法调试最后只能逐个补库。后来养成的习惯是任何自编译 adb 包到手先file后ldd再跑一轮百次重连通过了才进交付流程。这套流程看着啰嗦但能拦下大部分隐蔽问题希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑