news 2026/9/28 1:08:50

RKDevInfoWriteTool排障指南:SN/MAC写入失效与量产批处理方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RKDevInfoWriteTool排障指南:SN/MAC写入失效与量产批处理方案

产线群里又发来截屏:RKDevInfoWriteTool连不上板子,SN写进去重启又变回原样,MAC地址填错了格式批量写到一半报错。做RK平台量产的朋友应该都有同感,这个官方图形工具看着就几个输入框,但SN、WIFI MAC、BT MAC、以太网MAC怎么写、写到哪里、为什么“写成功”了却不生效,每一步都有坑。

这篇文章我打算按实际排障的顺序来,先讲清楚工具底层的写入机制,再逐个拆设备连接、SN写入、MAC配置这些高频问题,最后给一套能直接搬去用的Linux/Python批处理思路。无论你是BSP工程师、产测小哥,还是买了RK3568开发板想自己改SN的玩家,都应该能从这里找到对应问题的排查路径。

1. 先弄明白RKDevInfoWriteTool到底在改什么

1.1 它是瑞芯微官方的板级信息烧写工具

RKDevInfoWriteTool是瑞芯微官方提供的Windows图形化工具,通常能在SDK的RKTools目录里找到,也会随量产工具包发给代工厂。它通过ADB通道连接设备,对板级存储分区做读写,用来固化SN、WIFI MAC、BT MAC、以太网MAC等信息。

很多第一次接触的人会把它当成普通的“设备信息修改器”,其实它改的不是Android系统里的设置数据库,而是存放在专门分区里的原始数据。设备每次开机时,bootloader或者内核驱动会去这个分区读数据,再填充到系统属性、网络接口地址里。所以它的定位更接近“产线烧录工具”,而不是你在系统设置里乱点就能改的东西。

1.2 写入的数据到底存在哪里

RK平台早期的固件里,设备信息一般放在misc分区,后来逐渐独立出deviceinfo分区。RK3568、RK3588这些新平台的Android 12/13固件,通常可以看到/dev/block/by-name/deviceinfo。但部分方案商定制的固件会把信息塞到info、dinfo、vendor甚至U-Boot环境变量里,分区名各不相同。

这个差异是很多“工具提示成功但设备没变”问题的根源。你拿到的工具版本如果是按老平台分区格式来写的,而固件是方案商在新平台上改了存储布局的,那写入的位置可能压根没被系统读取。拿到新固件后,务必先执行ls -l /dev/block/by-name/确认实际分区列表,再去判断工具和数据是否匹配。

1.3 工具写入字段和系统读取路径的对应关系

工具字段常见存储分区Linux下读取路径Android属性/表现
SNdeviceinfo/misccat /proc/cmdlinegetprop ro.serialno
WIFI MACdeviceinfocat /sys/class/net/wlan0/address设置-关于本机-状态
BT MACdeviceinfohciconfig -a或getprop ro.boot.btmac蓝牙设置页面
以太网MACdeviceinfocat /sys/class/net/eth0/address设置-以太网

理解这条链路很重要。比如你给板子写入了新的WIFI MAC,但上层看到的一直是旧值,就要去查wlan0/address有没有变化;如果文件里已经变成新值,那是应用层缓存;如果文件里还是旧值,那就是驱动压根没读到工具写的东西。

2. 设备连不上:90%的故障卡在这一步

2.1 工具识别不到设备的常见原因

RKDevInfoWriteTool的使用前提是板子进入Android系统,并且USB调试已经打开。它走的是ADB协议,不是RK刷机工具用的Loader模式USB协议。很多人把板子按进Loader模式,拿着RKDevInfoWriteTool去连,工具肯定不识别。Loader模式请用RKDevTool或AndroidTool,这个一开始就要分清楚。

插上USB后,板子首次连接会弹出“允许USB调试吗”的确认框。量产现场经常是板子放在老化架上,没人去点确认,PC端adb devices显示unauthorized,工具自然一片空白。处理办法很简单:拔掉USB重插,在板子屏幕上点允许,勾选“始终允许”。

另外,ADB版本和驱动不匹配也常见。Windows上装了各种手机助手后,设备管理器里可能出现黄色感叹号,或者显示为“Android Composite ADB Interface”但实际驱动不对。建议只保留官方Google USB Driver,或者用瑞芯微驱动包里的ADB驱动,其他手机助手能卸就卸。

2.2 权限问题:非root固件基本写不了

这是最容易被忽略的一点。RKDevInfoWriteTool底层要直接用root权限操作块设备分区,所以固件必须是eng或userdebug版本。如果板子上刷的是user版本,工具能连上、能读取,但写入时会报权限错误,或者静默失败。

判断固件类型就一条命令:

adb shell getprop ro.build.type

输出如果不是userdebug或eng,先换固件。很多量产固件是user版本,这种情况有两种处理方式:一是刷一个带root的测试固件专门写号,写完再刷正式固件;二是让系统集成商提供一个支持adb root的userdebug产测固件。硬在user版本上折腾工具,最后大概率白费时间。

工具里点写入之前,建议先在命令行手动确认一遍:

adb root adb wait-for-device adb shell id

id输出uid=0(root)才是OK的。有些固件虽然支持adb root,但重新连接后权限又掉了,需要再执行一次。

2.3 USB线材、端口和虚拟机的连环坑

USB线的问题是我见过最多的。开发板、电视盒上的USB口很多只支持USB 2.0,你用一根USB 3.0的优质线去连,反而可能枚举失败。遇到连接不稳定,先换一根短的USB 2.0线试试,成本最低,见效最快。

如果是在虚拟机里跑RKDevInfoWriteTool,那坑更多。VMware默认的USB兼容性设置可能识别不到设备,或者设备和宿主机抢USB权限。我踩过的情况是:物理机Windows能看到设备,虚拟机里adb devices死活不出来。解决办法是:

  • 虚拟机设置里把USB控制器改成USB 2.0
  • 确认“自动连接新USB设备”是开启状态
  • 在菜单栏的“虚拟机-可移动设备”里手动把RK设备连接到虚拟机
  • 每次切换USB连接后,重新插拔一次数据线,并在虚拟机里执行adb kill-server和adb start-server

这里还衍生出一个判断技巧:如果你在设备里执行getprop ro.serialno或者查MAC,发现前缀是00:0C:29或08:00:27,那就要警惕了。前者是VMware虚拟网卡的OUI,后者是VirtualBox的OUI。这种地址表明你当前操作的对象很可能不是目标硬件,而是一个虚拟机里运行的系统环境,先检查自己的调试拓扑是不是串错了。

2.4 连接失败的自查命令与定位表

按下面这个顺序执行,基本能定位80%的连接问题:

# 宿主机执行 adb kill-server adb start-server adb devices -l adb shell getprop ro.build.type adb shell id adb shell ls /dev/block/by-name/
现象判断与处理
adb devices列表为空USB枚举失败,换线换口,检查设备管理器驱动
设备显示unauthorized板子上没点允许调试,重新拔插或点击允许
ro.build.type是user固件不支持写号,换userdebug/eng固件
adb shell id非uid=0没有root,执行adb root后重试
/dev/block/by-name/没有deviceinfo固件存储布局不同,确认分区名并确认工具版本匹配

3. SN写入翻车实录:格式、长度与“写成功但没生效”

3.1 写入报错:先会读,再会写

拿到一台新板子,不要上来就写。先点一下工具里的“Read/读取”,确认工具能不能把当前SN读出来。如果能读出来,至少说明ADB通道、分区访问、工具识别都是通的;这时候写失败,问题大概率出在分区只读、权限不够、或者工具版本和固件分区格式不匹配。

我在RK3399盒子上遇到过一次:工具能读取,点写入提示“Write Failed”,排查到最后发现是固件把deviceinfo分区挂载成了只读。更隐蔽的情况是,工具读取时走的是ADB广播通道,写入时却要走另外一套root shell命令,固件的su二进制被替换后写入命令执行失败。这种问题用adb shell手动跑一遍数据写操作就能暴露。

3.2 不同平台分区差异:分区名和偏移都可能变

RK3568、RK3588、RK3399、RK3288这些平台,从Android 7到Android 14,deviceinfo分区的偏移和字段布局一直在调整。早期平台可能在misc分区的固定偏移,新平台独立成deviceinfo,再往后又有方案商把SN放进U-Boot环境变量里。

拿到一份固件,先看设备信息分区到底是哪一个。不同平台常见分区名不完全一致,包括deviceinfo、info、dinfo等。具体可以这样确认:

adb shell ls -l /dev/block/by-name/ adb shell cat /proc/cmdline adb shell getprop ro.boot.serialno adb shell getprop ro.serialno

如果/proc/cmdline里已经有serialno,说明bootloader从某个区域读到了SN;再对比工具读取的值是否一致。不一致的话,说明工具写的区域并不是bootloader读取的区域,这是平台或方案商的定制差异,只能换配套版本的写号工具,或者直接改U-Boot环境变量。

3.3 为什么写成功后SN还是原来的值

这是群里问得最多的问题,通常有三个原因。

第一,写入的位置不对。工具写了一个独立的临时区域,但固件的读取逻辑根本不看那个位置。这种情况常见于开发板社区固件,固件作者自己移植了RK工具,但存储布局没对齐。

第二,系统属性缓存。Android启动早期会把serialno读成属性并缓存到ro.serialno,写入后立即查看属性,往往还是旧值。重启才能看到变化。但要注意,如果你确认分区里的值已经改了,重启还是没变,那就要往驱动或bootloader读取逻辑的方向排查,而不是反复重启。

第三,分区格式被截断。SN长度超过工具预期,比如目标分区只给16字节,你填了32字节,工具可能提示成功,但写入时会截断,读取回来的还是原值或者乱码。

排查链路建议这样走:

adb shell cat /proc/cmdline | grep serial adb shell getprop ro.serialno adb shell strings /dev/block/by-name/deviceinfo | grep -i serial

先确认分区里实际的字符串,再确认cmdline和属性里的值,就能定位是“写入失败”还是“读取链路问题”。

3.4 SN字符集、长度与产测脚本校验

SN不是随便填的。瑞芯微平台常见的SN规范是16字节定长,字符集建议只用0-9和A-Z,不要带中文、空格、下划线、特殊符号。因为SN最终会拼接进内核cmdline,空格和特殊符号可能导致解析错误,产线上因为SN里带了一个下划线导致MES系统对不上的情况我也见过。

长度方面,RKDevInfoWriteTool不同版本接受的长度不一样。老版本可能默认16字节,新版本支持到32字节甚至更长。但如果你用32字节的SN去写一个老工具支持的格式,可能会在某个偏移上越界,导致后面的MAC字段被覆盖掉。所以批量写号前,先看工具说明和固件支持的SN长度,别想当然。

如果产线用MES系统自动生成SN,要和开发确认大小写策略。工具以大写写入,MES里存的是小写,后续溯源就会对不上。我的习惯是:统一大写字母,写入后回读,再和MES条码做字符串完全匹配校验。

4. MAC地址配置避坑:格式、唯一性与离线写入方案

4.1 驱动其实只认“冒号分隔”这一种格式

MAC地址常见三种写法:00:11:22:33:44:55、00-11-22-33-44-55、001122334455。在Linux/Android驱动层,最终统一是以00:11:22:33:44:55这种字符串形式呈现的。RKDevInfoWriteTool的不同版本对输入格式要求不一,有的要求带冒号,有的要求不带。

稳妥做法是:先查看设备当前的输出格式,再照着填。

adb shell cat /sys/class/net/wlan0/address adb shell cat /sys/class/net/eth0/address

比如输出是00:11:22:33:44:55,工具里就按这个带冒号的格式填;如果工具明确要求16进制字符串不带分隔符,就填001122334455。不要靠记忆和习惯,直接对照当前系统输出最安全。

另外,WIFI MAC和BT MAC在很多RK固件中存在联动关系。部分固件会自动根据WIFI MAC加偏移生成BT MAC,如果你再手动填一个不相关的BT MAC,反而可能导致蓝牙地址冲突。写入前先确认固件是否存在这种逻辑,不要全凭想象。

4.2 批量写入时MAC重复等于给自己挖坑

产线图省事,给所有板子填同一个MAC,后果很严重:

  • 路由器和交换机的ARP表会混乱,一个MAC在多个端口/设备间跳变
  • 多台设备同时在线时,包经常被转发到错误节点,表现为丢包、掉线
  • WIFI场景下,AP看到同一台station地址来自不同BSSID,可能直接拒绝关联或频繁踢出

MAC地址必须唯一。理想情况是公司提前去IEEE申请OUI地址段,或者向模组厂商购买MAC资源池;如果都没有,那就用下面的动态生成方案。

4.3 用芯片96位ID生成稳定且唯一的MAC地址

瑞芯微平台每颗芯片都有一份唯一标识,通常叫chip id(96位十六进制)。不同平台的读取路径不一样,常见的有:

adb shell cat /proc/cpuinfo adb shell cat /sys/devices/platform/*/chipid

拿到96位唯一ID后,可以用哈希算法生成MAC:

import hashlib chip_id = "0123456789abcdef0123456789abcdef" # 示例:96位ID的16进制表示 digest = hashlib.sha256(chip_id.encode("utf-8")).hexdigest() data = bytes.fromhex(digest) mac = bytearray(data[:6]) # 保持单播(bit0=0),设置本地管理位(bit1=1) mac[0] = (mac[0] & 0xFE) | 0x02 print(":".join(f"{b:02X}" for b in mac))

这样每台设备生成的MAC几乎不可能重复。因为设置了本地管理位(locally administered),这个MAC不会和IEEE分配的全球唯一MAC冲突。缺点是少数严格校验OUI的网络环境会拒绝这类地址,但绝大多数家用和企业路由器都能正常使用。

实际上,很多RK方案固件内部已经有类似逻辑:如果deviceinfo分区里MAC为空、全是0或全是F,驱动会自动用chip id生成一个默认MAC。这也是为什么有时候你读到的MAC和写入值完全不同的原因。排查时先确认wlan0/address用的是哪个来源,再决定要不要手动写。

4.4 通过OUI前缀快速判断MAC环境

“000c:29开头的MAC地址是不是虚拟机”这个问题在技术社区很常见。答案是:是的。00:0C:29是VMware的OUI,VMware虚拟网卡默认使用的就是这段地址。08:00:27是VirtualBox的OUI,看到这个前缀基本可以断定是VirtualBox虚拟机。

这个知识在RK开发板的调试场景里很实用。比如你在一台虚拟机上搭建了编译环境,虚拟机桥接网卡用来和开发板通信,如果不小心把虚拟机网卡的MAC当成了开发板的MAC,就会出现“地址对不上”“MAC冲突”的迷惑现象。看到00:0C:29或08:00:27开头的MAC,先确认自己操作的目标是不是虚拟环境。

反过来,当你往RK开发板写入MAC后,可以用OUI数据库核对前三个字节,看看是否指向你使用的WIFI模组厂商或Rockchip自身。如果显示的是完全不相关的厂商,大概率是驱动又自动生成了默认MAC,而不是使用了你写入的值。

4.5 写到一半断电导致分区损坏的恢复

量产现场最怕的意外是写入过程中断电。deviceinfo分区损坏后,板子可能开不了机,或者开机后SN、MAC全是异常值。这种问题没有在线修复的捷径,只能重新烧写。

恢复步骤:

  1. 把板子重新进入Loader模式
  2. 用RKDevTool或AndroidTool重新烧写整个固件
  3. 如果只想恢复设备信息分区,单独勾选对应分区镜像,或者执行分区擦除再写号

产线工位一定要用稳定的电源,不要用PC的USB口直接给板子供电写号。USB供电在写入时瞬时电流波动大,容易在关键扇区写入时掉链子。

5. 绕过图形界面的Linux/Python批处理方案

5.1 量产场景为什么不能只靠图形工具

RKDevInfoWriteTool的问题在于:单机操作、图形界面、Windows依赖,遇到几十台甚至几百台设备排队写号时,效率和稳定性都跟不上。量产线上更合理的做法是:用脚本调度,一台一台自动写入、回读、校验、记录日志,再把日志同步给MES。

如果你只是临时在Linux主机上手动改一台设备的SN/MAC,可以直接操作分区。下面是一个最基础的分区备份与回写思路,具体分区名以实际固件为准:

# 先备份当前分区内容 adb shell "dd if=/dev/block/by-name/deviceinfo of=/data/local/tmp/deviceinfo.bin bs=1k count=64" # 拉回宿主机存档 adb pull /data/local/tmp/deviceinfo.bin ./

回写一定要谨慎,直接对块设备做全量覆写很容易把厂商扩展字段弄坏。正确流程是先读懂分区结构,再只改目标字段的字节,改完校验CRC(如果有的话),最后才回写。

5.2 Python调度ADB批量写入的思路

我建议产测程序直接用Python调用ADB,再封装一层业务逻辑:

import subprocess import csv def adb_shell(cmd, serial=None): prefix = ["adb", "-s", serial] if serial else ["adb"] result = subprocess.run( prefix + ["shell", cmd], capture_output=True, text=True, timeout=15 ) return result.stdout.strip() def write_sn_mac(serial, sn, mac): adb_shell("root", serial=serial) adb_shell("wait-for-device", serial=serial) # 这里以分区写入示意,实际可调用官方工具的CLI入口 # 必须根据自己固件的分区结构实现具体写入逻辑 print(f"[INFO] {serial} -> SN={sn}, MAC={mac}") # 回读校验 actual_sn = adb_shell("getprop ro.serialno", serial=serial) actual_mac = adb_shell("cat /sys/class/net/wlan0/address", serial=serial) if actual_sn != sn.lower() and actual_mac.lower() != mac.lower(): raise RuntimeError("verify failed") with open("devices.csv") as f: for row in csv.DictReader(f): try: write_sn_mac(row["serial"], row["sn"], row["mac"]) except Exception as e: print(f"[ERROR] {row['serial']}: {e}")

如果官方工具包提供了命令行模式,尽量用官方CLI,别自己造轮子。命令行模式的返回码、回读接口都比你手搓的dd命令可靠。

5.3 产测日志和失败重试机制

批量写号脚本必须做三件事:

  • 每一台都记录完整日志:设备序列号、写入时间、期望值、实际回读值、结论
  • 回读校验不能只看SN,MAC也要校验,因为MAC可能被驱动改写
  • 失败重试上限设为3次,超过后把设备标记为“待人工处理”,不要让它混进良品流

日志格式建议用CSV或者JSON,方便后续导入MES。这里最容易被忽略的是回读时序:写入成功后,部分固件需要重启才能让属性生效,所以校验逻辑要区分“立即回读”和“重启后回读”两个阶段。我通常写入完成后自动重启设备,等系统起来后再执行回读,这样校验的是真实生效值,而不是分区里的半成品。

6. 几个实战验证过的排查口诀

最后分享几条我在项目里反复用到的经验,都是踩坑踩出来的:

第一,adb shell id不是uid=0,后面所有操作都别做。很多工具在非root状态下写失败还是静默的,等发现时已经开始返工了。

第二,user版本、userdebug版本、eng版本三种固件对写号工具的支持完全不一样。拿到新板子第一件事不是把玩工具,而是确认固件类型。

第三,批量写号时MAC不能全填同一个,哪怕只有5台设备,放到同一个局域网里都会出问题。

第四,工具提示写入成功、回读也变了,但系统显示没变,先重启;重启还没变,就该查驱动是不是自动生成MAC了,或者bootloader读取的SN区域和工具写入区域根本不是同一个地方。

第五,每次拿到新固件,我先做一次“工具读取值 vs 系统实际值”的基线比对表,把SN、WIFI MAC、BT MAC、以太网MAC全部记录下来,然后再批量操作。这个习惯做过一次就知道有多值,能省掉后面大量返工时间。

RKDevInfoWriteTool本身不复杂,复杂的是你手上固件的定制程度。抓住“分区存储、链路读取、权限校验、格式适配”这四条主线,再奇怪的故障也能拆出答案。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 1:08:46

8086最小模式原理与实操:理解x86底层运行机制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:08:42

AT7456E无人机OSD芯片STM32驱动与SPI配置避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:06:24

GMSL链路配置核心:MAX96717 CFG引脚设计与调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:06:00

RK3588开发板USB调试与ADB连接排查指南:从识别到文件传输

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:05:55

嵌入式开发者的福音:Clang、LTO与可观测调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:05:15

基于YOLOv8的工地焊接面罩佩戴检测:从数据标注到部署全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华