☰
arm_adb-master_default.tgz 解包与 ARM 设备 adb 调试全指南
2026/10/22 14:34:09 网站建设 项目流程

简介:一份面向嵌入式与 Android 调试场景的 adb 工具完整源码包,适配开发者手动交叉编译生成不同架构的可执行文件。资源整体为 tgz 压缩归档,大小约 41.9MB,作者在 ARM 设备上实测编译通过,生成的 adb 可正常用于设备连接、shell 交互与文件下发等调试操作;平台暂未提供包内文件明细,因此不罗列具体目录。对需要在 arm/arm64/x86 等平台定制 adb 的工程师来说,可直接参照 README 完成构建,免去从源码收集依赖、排查环境的重复劳动,适合具备基础 Linux 操作能力的开发者和希望深入理解 adb 源码结构的读者。资源已有 180 人学习浏览,属于轻量但实用的工具源码,既能快速产出可用程序,也能作为 ADB 协议学习、交叉编译练习的参考。

1. 拿到 arm_adb-master_default.tgz 先别急着解压,它是 ARM 设备调试里最容易被低估的一个包

看到 arm_adb-master_default.tgz 这个压缩包时,十个工程师里有九个会先tar zxvf解出来再说,然后对着散落一地的二进制和脚本发呆半小时。这种事我干过不止一次。这个包名拆开看很直白:arm_adb 是面向 ARM 架构编译出来的 adb 调试工具集合,master_default 多数来自 SDK 的构建系统——master 是代码分支或发布通道标记,default 是默认配置工程,通常对应一块开发板或一个产品的基础配置。它解决的是标准 adb 在 ARM 目标机上“跑不起来、装不进去、连不上”这三类问题。下面我会从拆包前的判断开始,讲到装进设备、配通连接,最后把常见的翻车点按现象拆开讲。

2. 拆包前的三个动作:看清单、认架构、分清 adb 与 adbd

2.1 master 和 default 到底代表什么

先别急着把 tgz 当“版本号”看。我拿到这类包的第一件事,是把它当作“工程产物”来对待,而不是一个普通压缩包。master 在大多数 SDK 的发布流程里代表构建时的代码分支或发布通道,default 则更接近“默认配置工程”的含义。很多厂商的构建系统会为某块开发板维护一套 defconfig,或者干脆叫 default 工程,里面锁定了内核配置、库版本、编译选项,最后打包时就把分支名加配置名拼到了文件名上。换句话说,arm_adb-master_default.tgz 大概率不是某个人手动 tar 出来的,而是 CI 或发布脚本生成的。

为什么这个区分重要?因为它决定了你后续排查问题的方向。如果它是 CI 产物,包里的二进制会比较干净、可复现,碰到问题时应该优先怀疑运行环境;如果它是某工程师手工打包的,里面很可能混有本地路径、调试残留,甚至库版本和二进制不配套。我见过一个包,解出来 adbd 是新的,但配套的 libc 还是老的,装到设备上跑起来就段错误,查了两天才发现是打包的人忘了重新拷贝库。

另外,“default”不一定代表“官方推荐”。在很多 SDK 里,default 工程只是拿来验证编译链路的最小配置,连 adb 都不是默认开启的。所以你能在这个包里看到 adb/adbd,只能说明构建脚本包含了它,不能说明这套配置已经被产品验证过。拿到包后,第一件事不是看说明文件,而是看文件清单和二进制属性,这是下面两步要做的事。

2.2 tar -tzf 先看文件清单,不解包也能判断布局

很多人习惯直接tar xzvf,这是第一个翻车点。包里有几十个文件,没搞清楚布局就解包,往往把一堆 .so 和二进制散到当前目录,污染工程目录,后面还得一个个清理。更稳的做法是先用tar -tzf列清单:

tar -tzvf arm_adb-master_default.tgz | head -60

参数拆开讲:z表示 gzip 压缩,t是列出内容而不解包,v会输出权限、属主、大小、日期这些详细信息,f指定文件。head -60只是限制输出行数,防止文件特别多刷屏。我一般还会把结果存下来慢慢看:

tar -tzf arm_adb-master_default.tgz > manifest.txt wc -l manifest.txt grep -E "adb|adbd|\.so$" manifest.txt

这样做的意义,是让你在解包之前就对包的布局有预判。常见的 arm_adb 包内会有几类东西:adb 客户端、adbd 服务端、若干动态库、一个 .conf 或启动脚本,偶尔还有一份说明文档。如果包内只有一个 adb 可执行文件,没有 adbd,那这个包大概率只是给 ARM 宿主机用的客户端,不能直接拿来当设备端服务用;如果 adbd 和 adb 都在,多半是整套调试工具链。

还有一个容易被忽略的细节:查看 manifest.txt 时留意文件权限位。tar 会保留权限,如果包内 adbd 的权限不是-rwxr-xr-x而是-rw-r--r--,解包后直接跑一定会报权限错误。这种问题在手工打包的包里很常见,提前看到可以省一轮排障。另外,留意清单里的第一层目录:有的包顶层是一个arm_adb-master/文件夹,有的直接散在根上。有顶层目录的,解压时可以用--strip-components=1剥掉一层;散在根上的就得自己先建目录再解。我个人偏好先建空目录再解包,目录名带日期后缀,多个版本并存也不冲突。

2.3 file 与 readelf:确认二进制架构和动态依赖

清单只能告诉你“有什么”,不能告诉你“能不能在这块板子上跑”。下一步是确认架构,用file看二进制属性:

file adbd adb

典型输出大概是ELF 32-bit LSB executable, ARM, EABI5,或者ELF 64-bit LSB shared object, ARM aarch64。前者是 32 位 ARM 程序,后者是 64 位。这里要提醒一句:很多 default 工程在 ARMv8 平台上仍编译 32 位用户态程序,所以“板子是 64 位”不代表“必须用 aarch64 的 adb”,关键看你的用户态环境是 32 位还是 64 位。在设备上跑uname -m只能看到内核架构,要看用户态环境,用file /system/bin/sh或ls /lib这类实际文件更可靠。

file输出只能确认架构大类,还要看动态链接依赖。ARM 设备上最容易翻车的不是架构不匹配,而是缺库:

readelf -d adbd | grep NEEDED

这条命令列出 adbd 运行时需要加载的共享库。如果依赖里有libgcc_s.so.1、libc.so.6这类,你得确认设备系统里存在对应库且版本不低于编译时要求的版本。嵌入式 rootfs 为了精简经常砍掉一部分库,特别是libstdc++、librt、libpthread这些看似“不必要”的库。缺库的症状通常是 adbd 一启动就退出,dmesg 里看不到明显报错,非常容易误导排查方向。

另外,readelf -d输出里如果有RPATH或RUNPATH字段,也值得看。如果标了$ORIGIN,说明程序会优先从自己所在目录找库,你单独把 adbd 拷到别的目录,库找不到就会崩;没标则走系统默认路径。这两种情况拷贝策略完全不同。最后再用readelf -A adbd看 ARM 属性段,比如Tag_CPU_arch: ARMv7还是ARMv8。如果你的目标芯片是 ARMv7 平台,装 ARMv8 的包跑不起来;反过来把 ARMv7 的包塞进 ARMv8 平台通常能跑,但可能被新内核的 selinux 策略拦截。这个判断要提前做,不要等到 adbd 起不来才回头看。

3. 装入 ARM 目标机的两条路线:内置 adbd 与宿主机侧复用

3.1 路线一:把 adbd 放进设备系统

最常见的需求是把 adbd 装到 ARM 设备上,让 PC 端 adb 能连进去调试。这里分两类设备:Android 类(车机、电视盒子的系统镜像)和纯 Linux 类(工控屏、边缘网关)。Android 类设备一般已经有 adbd,包里的版本通常用于替换年久失修的旧版;纯 Linux 类设备才是这个包的主要用处,因为标准 Linux 发行版默认不装 adbd。

先建一个干净的临时目录再解包,别在工程根目录里直接解:

mkdir -p /tmp/arm_adb && cd /tmp/arm_adb tar xzf /path/to/arm_adb-master_default.tgz find . -maxdepth 3 -type f -name "adbd*"

解包后,先确认 adbd 存在,再拷贝到目标设备的可执行目录。Android 系统常见做法是放/system/bin或/vendor/bin,但多数可写系统需要 adb remount 后才能操作;纯 Linux 设备放到/usr/bin或/usr/local/bin都行。我一般先推到/data/local/tmp试跑,而不是直接覆盖系统里的 adbd:

adb push adbd /data/local/tmp/ adb shell chmod 755 /data/local/tmp/adbd adb shell /data/local/tmp/adbd &

这里把 adbd 先推到临时目录的原因,是调试阶段直接覆盖系统文件,一旦新 adbd 有问题,重新刷机才能救回来,代价太大。先在临时目录跑起来,确认稳定后再放到最终路径。注意chmod 755这一步不能省:adb push不会保留你本地的执行权限,推过去的文件默认是 644,少跑一次 chmod,后面就是权限报错。最后的&让 adbd 在后台运行,shell 退出后进程继续存在;如果设备有 init 管理(4.2 会讲),就不需要手动后台运行。

如果设备上原本有 adbd 而且在跑,替换前先备份:

adb shell cp /system/bin/adbd /data/local/tmp/adbd.bak adb shell /data/local/tmp/adbd.bak &

备份的回报在于:新 adbd 连不上或反复崩溃时,一条命令切回旧版,现场调试不至于卡死。

3.2 路线二:ARM 版 adb 客户端跑在 ARM 宿主机上

第二个需求容易被忽略:包里的 adb 客户端也能直接在另一台 ARM 设备上跑。很多嵌入式现场没有 x86 PC,只有一台 ARM 工控机当产测主机。标准 adb 发行版基本只有 x86_64 二进制,你在 ARM 主机上跑必然报 “Exec format error”,这时包里的 ARM 版 adb 就是应急通道。

./adb devices ./adb connect 192.168.1.100:5555

把包解压到 ARM 宿主机的某个目录下,用./adb显式调用,避免和系统里的 x86_64 adb 混淆。这里有个血泪教训:很多人把 ARM 版 adb 重命名成adb丢进/usr/bin,然后某天升级系统时被同名包覆盖,又变回 x86_64 版本,现场调试半天才发现调错了二进制。我现在的习惯是保留包的原始目录结构,用完整路径调用,或者建一个adbar别名,让它和系统 adb 明确区分开。

ARM 版客户端和 PC 版在功能上没有本质差别,adb shell、adb push、adb reverse都能用。但有一个缓存问题:adb客户端会在~/.android/adbkey生成一对 RSA 密钥,用于和设备端 adbd 做认证。如果你把 ARM 版 adb 拷到多台宿主机,且共享同一个 home 目录,多台主机会共用同一对密钥,插上设备时会遇到“已经信任但连不上”的诡异问题,清掉~/.android/adbkey*重新配对即可。

3.3 选型:什么时候用包内 adb,什么时候用系统自带

不是所有场景都需要这个 tgz 里的东西,选错了反而多一层麻烦。下面是我常用的判断逻辑:

场景推荐做法原因
设备系统里有可用的 adbd,只是版本旧先用系统自带,确认问题再替换避免引入架构或库依赖问题
纯 Linux ARM 设备,没有任何调试通道用包内 adbd 手动拉起最快的临时通道,不必重刷系统
ARM 宿主机需要调试另一台 ARM 设备用包内 adb 客户端(完整路径)x86_64 adb 在 ARM 机器上必然跑不了
想把调试能力固化到产品镜像不要直接拷二进制,建议重新编译或对照打包包里的库和配置未必适配你的 rootfs

表格最后一行多说一句:产品镜像里的 adbd,我一般不直接从这种分发包里拷贝,而是建议用同套 SDK 重新编译一次,至少要把依赖库一起放进镜像。之前在某项目的联调阶段,直接拷包内 adbd 替换,对方编译时用的 glibc 版本比我们镜像高了半个版本,adbd 起来就崩,最后重新编了一版才稳定。包能解开不代表你的系统能跑,这是最贵的认知。

4. 让 adb 在 ARM 设备上真正连得通:三处必调配置与最小验证序列

4.1 USB 权限与设备节点:udev 规则和 usb 模式

adb 连不上的第一道坎往往不在包内,而在 USB 权限。PC 端 Linux 默认不会给普通用户访问 USB 调试设备的权限,你可能lsusb看到设备,但adb devices永远空白或提示 no permissions。标准解法是写 udev 规则:

SUBSYSTEM=="usb", ATTR{idVendor}=="VENDOR_ID", MODE="0666", GROUP="plugdev"

把这行保存到/etc/udev/rules.d/51-android.rules,然后执行sudo udevadm control --reload && sudo udevadm trigger。这里的VENDOR_ID要换成实际设备的厂商 ID。设备连接后跑lsusb能看到,比如Bus 001 Device 002: ID 1234:5678里的1234就是。如果手头一时没有具体 ID,可以先adb kill-server && adb start-server重启 adb 服务重新枚举,但这只是缓解,不写规则每次插拔都要折腾一遍。

设备端同样有开关。Android 设备要在开发者选项里打开 USB 调试;纯 Linux 设备要看内核是否启用了 USB gadget 和 adb 相关功能。如果设备内核没有对应的 gadget 配置,USB 线插上去根本没反应,这种问题不是 adb 配置能解决的,得回到内核配置。所以我一直建议在选型阶段确认官方系统镜像自带 adb 支持,可以省掉一整层麻烦。

4.2 adbd 的监听配置:端口、tcpip 与 init 脚本

USB 通了之后,很多人还想要网络 adb。设备不在手边、只有 IP 可达时,这个功能很实用。配置网络监听的命令序列如下:

adb tcpip 5555 adb connect 192.168.1.100:5555

第一行的adb tcpip 5555通知设备端 adbd 切换到 TCP 监听模式,端口 5555;第二行让 PC 端主动连接。跑完adb devices,应该能看到192.168.1.100:5555 device,之后的操作和 USB 模式完全一致。想回到 USB 模式,插上线下adb usb即可。

如果是手动拉起的 adbd,没有 init 管理,默认监听方式可能不响应网络连接。Android 类设备可以这样设:

adb shell setprop service.adb.tcp.port 5555 adb shell stop adbd adb shell start adbd

setprop设置了 adb 服务的 TCP 端口属性,stop/start adbd是让 init 重启 adb 守护进程使配置生效。这三个命令的顺序不能混:先设属性,再停,再启。直接start adbd不会重新读端口配置。纯 Linux 设备没有setprop概念,可以用adbd -p 5555或环境变量指定端口,具体参数因编译选项而异,不确定时跑adbd --help看一眼。

对产品固化场景,与其每次手动 setprop,不如把 service 写进 init 脚本。Android 在 init.rc 里加一段,纯 Linux 在 systemd 或 sysvinit 加服务:

service adbd /system/bin/adbd user root group root shell disabled seclabel u:r:adbd:s0

disabled表示默认不启动,需要时再start adbd。seclabel这行在 Android 上尤其重要:如果你替换了系统自带 adbd,而 selinux 策略里没有为它定义域,init 会直接拒绝拉起。这个问题在 5.2 里还会碰到。

4.3 最小验证命令序列:从 devices 到 shell

配置完不要急着跑业务,先用最小命令序列验证通道真的通了。我的顺序是固定的:

adb kill-server adb start-server adb devices -l adb shell echo ok

kill-server和start-server用于清理旧状态。刚改过 udev 规则或换过 adb 二进制时,不做这一步,服务可能还拿着旧设备列表。adb devices -l列出设备,-l额外显示设备型号信息,能帮助区分多个设备。最后adb shell echo ok才是真正的验证:只要 shell 能跑,说明从客户端到服务端的链路已经打通,接下来可以放心做 push、forward、gdb 这些操作。多台设备同时连时,记得用adb -s <serial>指定设备,否则 adb 会报 “more than one device”。

这里有个常见误区:看到adb devices列出了设备就算成功。实际上 offline 状态的设备也会被列出,只是后面带 offline 标记,只有看到device才算可用。另外,连接网络设备时输出里可能会出现daemon started successfully这类信息,别慌,它们只是状态提示,最终以 devices 列表为准。

5. arm_adb 配套排查与避坑:offline、反复重启与权限玄学

5.1 现象:adb devices 能看到但一直 offline

这个问题的出现频率最高。现象是adb devices里设备在列,但状态是 offline,等多久都不变。

原因绝大多数时候是 adbd 版本和 adb 客户端的协议不匹配,或者设备端 adbd 已经进入半死不活的状态(服务异常但进程没退)。还有一种少见但真实的情况:USB 线质量差或用了延长线,传输层不稳定,设备反复断开重连,最终停在 offline。

解决方式是按层级来:先重启两端服务——PC 端adb kill-server,设备端把 adbd 进程杀掉或直接重启;无效就换 USB 线,几十块的充电线能充电不代表能传数据;还不行就考虑协议版本,把 PC 端 adb 换旧一版试试,因为新版客户端对认证和握手流程更严格。我踩过最深的坑是设备端 adbd 协议版本偏老,PC 端 adb 太新,握手信息对不上,最后降级 PC 端 adb 才解决。

5.2 现象:adbd 启动后反复重启

手动拉起的 adbd 出现“起来一下、过几秒消失”的情况,是另一类高频翻车。先看日志:Android 上跑logcat -d | grep adbd,纯 Linux 设备看dmesg | tail或journalctl。

原因通常有两个方向:一是缺少动态库依赖,adbd 启动时加载失败,脚本或 init 又把它拉起来,形成死循环;二是 selinux 权限拦截,Android 系统里如果 adbd 的上下文不对,内核会在启动时直接杀掉进程。还有第三种,adbd 端口被占用,起第二个实例时 bind 失败退出,脚本又反复拉起。

解决:缺库就用 2.3 里的readelf -d逐个核对,缺哪个补哪个;selinux 问题在测试设备上可以临时setenforce 0确认,确认后把 seclabel 和策略修正;端口占用用netstat -tlnp | grep 5555或lsof -i:5555找占用进程。手动拉起的 adbd 如果反复被杀,还要确认运行用户权限——有些 adbd 编译时要求 root 身份,用普通 shell 用户拉起会直接退出。

5.3 现象:adb push 到一半断连,报 permission denied

push 大文件或连续 push 多个文件时,传输中断或报failed to copy ... Permission denied。

第一个原因是目标目录的写权限。adb push默认用 shell 用户身份,很多系统目录 shell 用户没有写权限,比如/system这类分区还得先 remount。第二个原因是设备端存储空间不足或 inode 用尽,adb pull有时反而能成功,所以容易被误导成“只有 push 有问题”。第三个原因是 adbd 的连接数或内存限制,网络 adb 模式下更容易触发。

解决:先 push 到有权限的目录,比如/data/local/tmp,再在设备端用mv移动到最终位置;检查df -h和df -i;网络模式传大文件时改回 USB 模式。我个人习惯是大文件一律先传到/data/local/tmp,校验大小后再移动,这样即使断连,重传代价也小。

5.4 现象:ARMv7 的 adbd 在 64 位系统上直接段错误

设备能跑起来,但 adbd 段错误,或提示cannot execute binary file。这个问题在 2.3 提过,这里展开。

原因是架构不匹配:目标系统用户态是 aarch64,而你塞进了 armv7(32 位)的 adbd。如果报的是段错误而不是“无法执行”,说明内核开启了 32 位兼容支持,能加载程序但运行时兼容层有问题,比如缺少 32 位动态库。

解决:确认用户态架构后,找对应的 aarch64 或 armv7 版本。不要以为“都是 ARM 就通用”,ARMv7 和 AArch64 的指令集、调用约定、动态库路径都不兼容。如果这个 tgz 里两种架构都有,一定按file输出选,不要按文件名猜。踩过这个坑的人,现在都会在解包后第一时间做一次find加file的混合遍历,把全部二进制体检一遍。

5.5 现象:包内 adb 版本太老,认不了新设备

这个坑在旧 SDK 的包里特别多。现象是包内 adb 在 PC 上运行正常,但连较新的手机或开发板时,设备列表能看到,状态一直是unauthorized或device unknown。

原因是新版 Android 的 adb 认证协议升级了,旧版本客户端没有对应的密钥处理逻辑,或者设备端 adbd 要求的协议版本高于客户端支持范围。这不是配置问题,是版本断层。

解决:优先用包内的 adbd 服务端,PC 客户端换用较新的版本。客户端和服务端版本不要求一致,只要握手协议兼容即可。反过来,如果 PC 端 adb 无法更新,就别硬连新设备,改用串口或网络方式进入系统。我曾经在某项目的产测工具里用混搭方案:设备端用包内 adbd(定制过,必须用),PC 端用新版 adb 客户端,握手完全没问题。

6. 进阶:把 arm_adb-master_default.tgz 变成一套可复用的调试工具链

6.1 用 adb forward 打通设备内网端口

调试嵌入式设备时,设备端往往有 web 服务、modbus 服务或 gdb server,但网络隔离让 PC 直连不了。用adb forward把设备端口映射到 PC 上,立刻就能访问:

adb forward tcp:8080 tcp:80 adb forward tcp:2345 tcp:2345

第一条把设备的 80 端口映射到本机 8080,浏览器打开http://127.0.0.1:8080就能看到设备上的服务页面;第二条是 gdb 调试常用,把设备的 gdbserver 端口透传到本地。这比改防火墙配路由快得多,而且走 adb 通道,不受局域网环境影响。

6.2 把常用验证动作固化成一个脚本

每次调试都敲一遍重复命令容易漏,尤其是换设备、换环境后。我习惯把第 4 章的最小验证序列固化成脚本,放在包外面而不是包内,避免污染原始文件:

#!/bin/bash adb kill-server adb start-server adb wait-for-device adb shell echo "adb link ok" adb shell getprop ro.product.model

wait-for-device会阻塞直到设备出现,适合放进自动化脚本里避免顺序问题。这样每次拿到新的 ARM 设备,解包、校验、跑脚本,几分钟内就能确认调试通道可用。

这套 tgz 用久了你会发现,真正的价值不在那个 adb 可执行文件本身,而在它让你在设备启动早期就有了一个可控的调试入口。我现在拿到任意的分发包,第一件事永远是tar -tzf看清单、file看架构、readelf -d看依赖,这个习惯救过我至少三次,也让我在新板卡面前少出了很多洋相。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询