ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RKDevInfoWriteTool写号工具详解:SN与MAC地址配置及常见问题排查

RKDevInfoWriteTool写号工具详解:SN与MAC地址配置及常见问题排查 1. 认识RKDevInfoWriteTool它不是刷机工具而是“写号工具”做瑞芯微平台开发或者生产的朋友对这名字应该不陌生。RKDevInfoWriteTool国内工程师一般叫它“瑞芯微写号工具”官方名称是Rockchip DevInfo Write Tool。它最常见的用途就是把SN序列号、MAC地址、设备型号这些信息写进板子的固件分区里。先说清楚一个容易混淆的点它不负责烧录固件烧录镜像用的是RKDevTool或者工厂用的升级工具。RKDevInfoWriteTool负责的是“出厂参数写入”也就是量产出货前最后一哆嗦。板子硬件贴好了、固件刷好了、系统能开机了再用它把每一台机器唯一的SN、MAC地址写进去。如果没有这一步几十上百台板子全是同一个MAC、同一个SN进路由器一查全是相同IP后台也没法区分设备产品根本没法卖。这篇文章写给三类人一是产线负责烧录测试的工程师二是做嵌入式BSP或系统集成的开发三是在学校、实验室用瑞芯微开发板DIY项目的同学。我不会照着官方文档翻译一遍而是把我实际用过、踩过、帮别人擦过屁股的经验整理出来。你能看到常见报错长什么样、为什么会有这个问题、以及正确的处理顺序。2. 工具工作原理与配置烧录器接口解析2.1 写号到底写进了哪里RKDevInfoWriteTool并不是用系统里的ioctl随便改一下网络配置就完事。它通过USB把数据写到板子的固定分区这个分区在Rockchip平台的方案里一般叫parameter分区或者专门的misc/deviceinfo分区。以RK3568这类平台为例系统起来后会读取分区里的SN、MAC信息然后把这些信息暴露给系统层。Android端能看到的是/sys/class/ddr/device/snLinux端常见路径是/proc/device-tree/serial-number网络接口的MAC地址则是由驱动在初始化时从分区读出来的。也就是说你写进去的不是“临时配置”而是固化到分区里的“出厂数据”。就算恢复出厂设置、重新刷系统只要不动这些分区SN和MAC都还在。正因如此写号工具本身并不复杂但它的“权限”很大。写错一个字节可能导致设备网络异常或者SN与后台数据库对不上返工成本非常高。2.2 configuration烧录器文件的真正作用打开RKDevInfoWriteTool压缩包你能看到config目录下有一个configuration文件没有扩展名用记事本打开就能看到内容。很多新人把它当摆设其实它决定了工具能写哪些分区字段顺序是什么。[Write] sntrue mactrue device_idfalse ...实际配置项会根据工具版本略有区别但核心逻辑一致某个字段配成true工具就允许你写配成false就算界面里填了也写不进去。这里有一个很容易踩的坑如果你拿到了一个别人给的工具包configuration里可能把sn配成false导致无论怎么填写入都报错。遇到这类问题时第一反应不应该是怀疑USB线或者驱动而是先打开配置文件确认开关状态。2.3 工具版本与芯片平台的匹配关系瑞芯微不同芯片使用的写号工具版本不完全一样。RK3288、RK3399的老项目可能配套的是1.x版本的工具RK3566、RK3568、RK3588的新项目一般用2.x以上版本。注意这不代表高版本一定兼容低版本。老工具面对新平台的分区结构会不识别新工具拿到老平台也未必稳定。最靠谱的方法是使用SDK发布包里tools/linux/Linux_Driver和tools/windows/RKDevInfoWriteTool里自带的那个版本而不是从网盘里随便找一个通用版。从底层来看写号工具的运行流程大致是USB枚举设备 → 进入Maskrom/Loader模式 → 识别分区表 → 在指定偏移处写入数据 → 读取校验。任何一个环节出了问题都会表现为不同的报错形态。这也是为什么排查时要按照“接线状态 → 模式状态 → 配置状态 → 写入结果”的顺序来而不是瞎猜。3. SN、MAC地址配置实操全流程3.1 环境准备清单在动手之前先把环境准备好。我整理了一份最小清单缺一样都可能在中途卡住一台Windows电脑最好Win7或Win10Win11也见过有人用但驱动兼容性看运气瑞芯微驱动 DriverAssitant版本要与工具配套一台瑞芯微开发板或设备支持进入Loader模式双头USB线注意是双A口USB线不是Type-C不是USB转串口线从SDK包中解压出的RKDevInfoWriteTool完整目录驱动安装有个细节Windows 10以上系统会强制签名校验如果你的驱动没有签名开机要选择“禁用驱动程序强制签名”。这步不做后面设备管理器里永远显示一个黄色感叹号的未知设备。3.2 填写关键参数SN、MAC、设备ID启动工具后界面很简单几个输入框加几个按钮。核心字段就这几个SN序列号一般由数字和字母组成长度根据你们公司的编码规则常见是16位或32位MAC网卡的MAC地址格式为AA:BB:CC:DD:EE:FFDevice ID部分项目会用到比如云端识别设备唯一IDHDMI/HDCP Key如果产品需要播放受保护内容这里会涉及MAC地址不是随便填的。前3字节是OUI组织唯一标识符向IEEE申请或购买。很多公司会买一个OUI比如00:0C:29、A4:5E:60这种。后3字节是厂商自己分配的在同一OUI下保证唯一。如果你在实验室里测试没有申请到的OUI可以用常见的本地管理地址比如02:00:00:xx:xx:xx。但量产千万别这么干原因是本地管理地址在某些网络环境里会被网关特殊对待容易触发奇怪的问题。关于网上流传的“000c29开头的MAC地址都是虚拟机吗”这个问题我多说一句。00:0C:29确实是VMware默认分配的OUI区间很多虚拟机的虚拟网卡MAC都以它开头。但在实际排查网络故障时不能只看前三位就断定对方是虚拟机因为有些硬件厂商也买了这个OUI下的地址段用户手动修改过MAC为这个前缀路由器、交换机等管理设备也可能是这个前缀正确的姿势是结合完整的MAC地址、主机名、操作系统TTL值、开放的端口综合判断。这个问题的本质不是“这个前缀是不是虚拟机”而是“如何准确识别网络中的设备类型”这在做网络调试时非常实用。SN的生成规则建议用“日期批次序号”比如20250611A0001。这种方式的好处是过半年后你看到一段SN能直接知道是哪天生产的、是哪个产线、第几台排查问题效率高很多。千万别用纯数字流水号也别带容易混淆的字符比如O和0、I和1不然后面人工抄录、拍照存档时会痛苦到怀疑人生。3.3 完整写入操作步骤第一步先给板子上电确认能正常开机进入系统或者至少进入Loader模式。不同设备的进入方式不一样常见的是按住板子上的Recovery键再上电或者通过ADB命令adb reboot loader。RK3568开发板常见的是按住Loader键同时插USB。第二步用双头USB线连接电脑和设备。如果设备进入Loader模式成功Windows的设备管理器里会多出一个Rockchip USB设备设备名通常是Rockchip Loader。第三步运行RKDevInfoWriteTool.exe。工具会自动检测设备。如果界面左下角显示绿色文字说明检测到了如果没有依次检查驱动、USB线、连接方式。第四步填入SN、MAC等信息。注意MAC地址的分隔符有些版本工具要求用冒号:有些版本支持中划线-但写入前会自动格式化。为了保险统一用冒号格式。第五步点击“Write”按钮工具会开始写入。写入过程中不要拔USB线不要给板子断电。整个过程通常几秒钟。第六步写入完成后点击“Read”按钮读取刚写入的分区内容回读出来的信息应该和你填的一致。这一步很多人会忽略但它相当于“确认收货”建议养成习惯。3.4 验证写入结果的方法工具回读只是第一层验证。系统层面的验证更贴近实际使用。板子正常启动进系统后执行以下命令确认SN是否正确cat /proc/device-tree/serial-numberMAC地址的确认方式取决于系统Linux系统ip linkAndroid系统开发者模式下settings get global sn ifconfig eth0如果系统里的值和你写入的值一致这一步的配置就算闭环了。如果系统里读出来不对问题不一定在写号环节也可能是设备树里没有配置好读取路径这点我在第4节详细说。4. 排查实录高频问题与处理方案前面操作流程看起来很顺但现实中会遇到各种幺蛾子。下面这些场景都是我实际遇到或者帮别人排查过的按出现频率排序整理了排查思路。4.1 插上USB后设备管理器不识别工具显示“No Device”这个问题占了求助帖的一半以上。排查顺序按下面来第一确认是双A口USB线。有些同学手边随便拿了根打印机USB线一头方口一头A口插不进去很正常。还有些线只能充电不能传数据遇到这种线设备管理器里什么都看不到。第二确认板子确实进入了Loader模式而不是正常开机。最简单的方法是看板子上的LED或者屏幕状态。更可靠的是打开RKDevTool看是否有设备识别如果RKDevTool能识别但写号工具不识别说明是工具版本不匹配如果RKDevTool也不识别那就是驱动或者硬件连接问题。第三重装驱动。先卸载旧驱动插着设备的情况下右键设备管理器里的未知设备选择更新驱动指向DriverAssitant的解压目录。装完之后拔掉USB重新插。有一个经验很多时候问题出在USB口上。台式机尽量用机箱后面板的USB口不要用USB Hub尤其是那种没有外接供电的Hub。笔记本如果插某个USB口不行换一个口试试常有惊喜。4.2 工具能识别但点击写号提示写失败报错信息五花八门常见的一种是写入超时或者校验失败。先检查configuration文件里的开关有没有打开再检查板子存储空间是不是满了最后考虑是不是分区被原系统占用。排查逻辑是写号工具写入时需要独占访问分区。如果板子系统已经正常启动挂载了该分区工具去写的时候可能因为分区被占用而失败。解决方法是先让板子进入Loader模式不要在正常系统下尝试写入。这个问题我见过最离谱的一例是因为板子上插着一张SD卡系统从SD卡启动写号工具写的是eMMC里的分区两边对不上。拔掉SD卡、从eMMC启动后问题消失。遇到写失败时先把能拔的外设都拔掉再逐个试能省很多时间。4.3 写入成功但系统读出的MAC是全FMAC读出来是FF:FF:FF:FF:FF:FF这说明设备树中MAC地址的读取路径没配对驱动根本没读到有效值。瑞芯微平台中MAC地址的读取链路通常是这样写号工具写入分区 —— bootloader/uboot 读取并存进环境变量 —— 内核设备树获取 —— 网卡驱动解析如果uboot没有把分区的MAC读到环境变量里内核设备树里就会得到空值或非法值最终表现为全F或者全0。排查方法在uboot命令行里执行printenv ethaddr看uboot层是否已经有正确的MAC如果uboot层就没有问题在uboot配置需要检查uboot代码中MAC读取部分的配置如果uboot有、内核没有问题在设备树中。以RK3568为例设备树中以太网节点的MAC地址读取一般通过读取efuse或分区里的值。需要确认设备树里配置了对应的别名和路径。比如gmac1 { phy-mode rgmii; clock_in_out input; snps,reset-gpio gpio3 RK_PB1 GPIO_ACTIVE_HIGH; status okay; };这类配置本身不直接包含MAC地址但它的地址读取依赖uboot传入的local-mac-address属性。如果uboot没有做好这个传递设备树写得再完整也没用。一个快速验证方法在系统启动后用root权限手动设置MAC地址命令是ifconfig eth0 down ifconfig eth0 hw ether 00:11:22:33:44:55 ifconfig eth0 up如果这样设置后网络能正常工作说明是读取链路问题如果设置后依然不通那是网卡驱动本身的问题需要用dmesg看驱动报错。4.4 写入的SN在系统里读不到工具写入成功回读也正常但系统里/proc/device-tree/serial-number是空。原因多半是设备树中没有配置optical的serial-number节点或者内核没有把分区里的SN传送到设备树中。检查方法cat /proc/device-tree/serial-number如果文件不存在说明设备树里根本没这个节点。需要在内核设备树里增加对应的chosen节点chosen { bootargs ...; serial-number 0000000000000000; };注意serial-number这个值在使用时会被bootloader动态覆盖。也就是说设备树里可以写一个占位符实际值由uboot启动时从分区读出来替换进去。所以看到占位符不要慌优先检查uboot是否执行了替换逻辑。还有一点容易被忽略SN和MAC不一样它是纯字符串没有统一的校验格式工具写入时也不会检查长度和字符范围。有些系统里的SN判断逻辑会对字符集有要求比如仅允许大小写字母和数字。你的SN如果带了下划线或者横杠部分校验严格的系统会直接判为非法SN。建议SN规则里限死在[A-Za-z0-9]范围内。4.5 产线批量生产时MAC重复或冲突这是量产的经典问题。手工填MAC一百台之内看不出问题一旦上千台Excel表一排序很容易出现两张表重叠或者某台流水线机器被反复填入了同一个MAC。我的建议是稳扎稳打地建一个“MAC地址池”流程买OUI后剩余的3字节有24位理论上有1600多万个地址用Excel或者SQLite按批次预先分配地址段每台设备写入后立即记录对应SN和MAC的映射关系出库前用扫码枪扫描校验确保一机一号这个流程听起来很基础但很多小团队是真没做。我见过一个做安卓工控机的客户因为没有管理MAC地址池把两百多台设备的MAC都写成了一样的导致客户现场的服务器把所有设备识别成了同一台机器最后是挨个返厂重新写的损失不小。从技术角度看写入时MAC地址的生成规则要求每个地址在OUI下唯一且不能与本机其他网卡冲突也不能是广播地址最后一位为01或多播地址第一字节末位为01。简单说就是第一字节不要设置成奇数最后一字节不要FF其他看你们自己的分配规则。4.6 工具回读正常但网络中MAC地址变成了随机地址有些平台默认开启了MAC地址随机化。Android系统从9.0开始默认对Wi-Fi启用随机MAC地址。如果写了MAC却发现连接Wi-Fi后路由器里显示的MAC不是写入的那个可能是系统随机MAC机制在起作用。排查方法进入系统设置 → Wi-Fi → 当前连接的无线网络 → 查看“MAC地址类型”看是不是“随机MAC”。或者通过ADB方式adb shell cmd wifi status如果确认是随机MAC机制导致的可以在设备树或系统属性里关闭随机化。Android系统中通常用以下属性wifi.interface.ignore_random_mactrue这个属性和设备型号、Android版本相关不同ROM的设置位置差异很大。如果找不到设置项也别硬找直接在业务层通过接口获取真实MAC来绑定用户比和系统机制硬对抗更省事。4.7 瑞芯微RK3568设备树中的MAC地址读取配置继续说RK3568设备树因为这是目前最火的一块瑞芯微芯片收到的相关问题也最多。RK3568有两个GMAC控制器分别是gmac0和gmac1。它们从哪读MAC地址取决于uboot准备把哪个地址放到哪根总线里。在实际调试中我看到的一种典型配置是在dts的根节点附近定义ethernet0: ethernetfe2a0000 { compatible rockchip,rk3568-gmac; ... };而MAC地址的读取逻辑通常在uboot代码里文件路径一般是u-boot/board/rockchip/rk3568/rk3568.c里面会根据fuse和config烧录器的信息来设置ethaddr。排查时可以这样走在uboot命令行执行mac命令查看MAC信息执行printenv ethaddr确认环境变量是否被正确设置如果环境变量是空的检查uboot里CONFIG_ROCKCHIP_EFUSE是否开启如果efuse里也是空的确认有没有在写号工具中把MAC写到对应分区有一种情况比较坑UBoot环境变量里设置了ethaddr但它不是从分区读的而是编译时写死的。这样所有开发板都会共用同一个MAC。如果调试时发现多块板子MAC都一样建议先查uboot的默认环境变量。4.8 虚拟机MAC地址与物理设备写号的混淆这个话题和上面的搜索结果“000c29开头的MAC地址都是虚拟机吗”高度相关放在这里一并说。在调试网络或批量管理设备时经常要区分虚拟机和物理机。00:0C:29这个OUI确实是VMware申请用于虚拟机网卡的所以在生产环境里看到的概率很高。但这个判断不是绝对的原因我在3.2节说过。判断逻辑应该是先看完整MAC用IEEE OUI查询工具查厂商如果显示VMware再看主机的其他特征网卡型号显示为Intel PRO/1000 MT Desktop而实际设备列表里没有对应物理硬件系统启动时间异常比如一开机就大量发包通过SNMP协议读取系统描述字段我再补充一点在写号场景中如果你们的自动化测试环境基于虚拟机而且虚拟机使用桥接网络请留意虚拟网卡的MAC可能会被宿主机虚拟交换机改动。某些虚拟化平台默认会开启MAC地址伪装导致虚拟机发出去的报文的源MAC和配置的MAC不一致。排查网络故障时要先确认虚拟交换机是否默认改了MAC否则会得出“写号不生效”的错误结论。5. 进阶排查从系统日志与设备树中反向定位问题前面的实操已经覆盖了大多数常见场景但这行总有意外。当常规手段都试过还是搞不定时就得从日志和设备树入手像侦探一样反向定位。5.1 从dmesg日志找线索写号工具写入成功之后如果系统启动阶段有问题内核日志里通常会有提示。尤其是在网卡初始化失败时dmesg里会打印类似rk_gmac fe2a0000.ethernet eth0: no valid MAC address found, using random这行日志已经足够说明问题驱动没有找到有效的MAC地址随机生成了一个。看到这行日志就是确认了刚才说的问题。接下来按4.3节的方式查uboot和设备树。其他值得关注的日志关键词ethernet: Failed to set MAC addresssn: not foundReading from partition ... failed日志比界面提示更底层提供的信息量也更大。养成在遇到问题先拉日志的习惯比反复插拔USB有效率得多。当然这行日志不是随便就能看到的。串口接出来看内核log的概率比较大如果板子没有串口就用dmesg | grep -i mac排查。5.2 从分区读取原始数据确认写入位置当你说不清到底是写号工具没写进去还是系统没读出来时最直接的办法是读取分区原始数据用hexdump查看。这样可以绕过所有中间层判断最根本的事实。举例假设分区是/dev/block/mmcblk0p5在板子系统上执行dd if/dev/block/mmcblk0p5 of/tmp/sn_partition.bin bs1 count64 hexdump -C /tmp/sn_partition.bin注意这里盲写有风险确保输入输出路径正确否则可能读到错误分区。一般做法是先看分区表cat /proc/partitions找到正确的分区节点。如果是bootloader层的问题就需要读取loader分区的数据然后对照写入工具的源文件逐字节比对。这一步门槛高一些但只要是正规产品开发工具链和源码是有的花点时间一定能定位到问题。5.3 修改设备树后重新编译的注意点当你确定是设备树问题需要修改并重新编译时有几点提醒第一设备树修改的是内核侧的dts不是bootloader的。RK3568的dts一般在内核源码的arch/arm64/boot/dts/rockchip/目录下。第二改完dts之后如果只替换了kernel.img有些平台会要求同步更新dtb两个文件要配套烧写。如果只刷了kernel不刷dtb可能出现版本不一致导致新配置不生效。更稳妥的是通过SDK提供的编译脚本一起生成boot.img和resource.img。第三设备树如果加了一个不存在的节点内核可能不会报错而是忽略。所以要对自己加的节点做语法检查dtc -I dtb -O dts -o output.dts boot.dtb把生成的dtb反编译成dts检查节点是否真的编译进去了这一步能排除“改了没用”的尴尬。6. 生产与批量管理的实战避坑这部分的内容在量产测试中遇到过总结下来希望对各位有借鉴意义。6.1 管理“责任田”SN与MAC映射记录的维护方式很多人用Excel管理SN和MAC其实这并不算一个好选择。Excel在数据量大时容易误操作行与行列与列看起来费劲而且多人协作修改版本容易错乱。我建议用一个简单的CSV文件加版本管理或者直接上SQLite数据库。每条记录至少要包含这些字段sn,mac,model,production_date,operator,status 20250611A0001,00:1A:2B:01:02:03,RK3568-IPC,2025-06-11,zhangsan,flashed 20250611A0002,00:1A:2B:01:02:04,RK3568-IPC,2025-06-11,zhangsan,flashed这里的关键点是status字段。它有可能是flashed已写入、verified已验证、shipped已出库。当设备在产线上流转时不同阶段对状态有严格要求。比如出库时如果state不是verified说明这台没有完成验证不允许出货。这种管理方式前期看起来比Excel“麻烦”但当你的产量超过一万台时这点前期投入能避免巨大的后续损失。毕竟每一台设备的SN和MAC都是独一无二的身份标识一旦混淆整个运维体系都要跟着乱。6.2 自动化脚本批量写入如果产线测试环境允许可以写一个简单的Python脚本调用工具的命令行接口实现自动写号。RKDevInfoWriteTool虽然主要用于图形界面但它在某些场景下支持命令行参数调用具体情况取决于具体版本。举个例子如果你的产线是Python驱动一体化设备可以用subprocess调用工具import subprocess import csv with open(device_list.csv, r) as f: reader csv.DictReader(f) for row in reader: cmd [ RKDevInfoWriteTool.exe, -sn, row[sn], -mac, row[mac], -device_id, row.get(device_id, ), ] result subprocess.run(cmd, capture_outputTrue, textTrue) if Write success in result.stdout: print(f{row[sn]} OK) else: print(f{row[sn]} FAIL: {result.stderr})注意这只是一种抽象写法具体参数名和工具支持情况要看你手里的版本。重点思想是自动化写号要把“人工判断”变成“程序校验”每写一台立刻回读对比不一致就标记FAIL。让机器做它擅长的事让人做判断和分析。6.3 防止产线“串号”产线最容易发生的问题是串号。比如测试时拿错板子或者写号工具同时连接两台设备导致写入对象错了。防止方法写号工具一次只连接一台设备。批量测试时用夹具控制USB通路一次只让一台设备接入电脑。另一个防串环节是批次管理。每批次产品使用的SN区间要提前划分好写入前人工目检SN贴纸和系统信息是否一致。不怕慢就怕错。一个SN写错导致客户投诉、返工整批产品的损失比产线慢半小时大多了。6.4 升级固件后SN和MAC是否会丢失这个问题的答案取决于升级方式。如果用RKDevTool烧录完整固件并且固件包里的parameter分区表不包含devinfo分区那么SN和MAC通常不会丢。但如果烧录镜像时使用了“擦除全部”或整体镜像包含devinfo分区SN和MAC就会被覆盖。所以量产流程一般有两种思路先烧固件再写号最后整体测试这样即便升级也不会覆盖先写号再烧固件但烧录时跳过devinfo分区用工具的分区管理功能实现两种思路都可行但在实际中我见到的产线一般优先使用第一种原因是写号工具在最后操作能确保出货前每个设备的参数都是最新的不容易被中途其他环节覆盖。7. 最后的经验之谈与操作习惯建议7.1 四步走排查思路遇到任何写号异常先冷静按照这个顺序排查90%的问题都能定位先确认传输链路驱动是否装好、设备是否枚举成功、USB线是否正常再确认工具配置configuration开关、工具版本、分区表是否匹配再确认写入结果工具是否回读成功、分区原始数据是否已经变化最后确认系统读取uboot环境变量、内核设备树、系统接口、网络实际行为这个顺序是有逻辑的从底层到上层每一层都验证清楚再去下一层。很多同学遇到问题直接看系统层的表现系统显示MAC不对就开始改设备树但实际根因是USB线接触不良导致写号根本没成功白白浪费几个小时。7.2 我踩过的一个最隐蔽的坑最后分享一个我印象最深的案例。有一次给客户做RK3568工控机写号工具显示写入成功回读也正常但系统里MAC就是不对。排查了整整一天uboot环境变量、设备树、内核驱动都看了一遍都没发现问题。最后偶然发现客户设备里插着一张带网口扩展的底板底板上的PHY芯片和核心板的GMAC1连接但这个底板是第三方做的它把核心板的GMAC1引脚复用成了其他功能。所以内核在初始化GMAC1时根本找不到PHY自然就起不来网络系统才用了GMAC0。而GMAC0根本没接外设驱动里用了随机MAC。所有问题在于客户用了非标准的核心板底板方案。这个案例给我们的教训是排查问题不能只盯着软件链路硬件上“实际网络走哪个接口、PHY接在哪”也要先确认。很多时候你以为在改GMAC1的MAC系统实际用的是GMAC0等于你在楼上修楼下的门锁当然怎么修都没用。7.3 给你的建议写号工具看起来简单但真正用好的关键是对整个启动链路有清晰的理解写号工具是源头uboot是传递者内核设备树是衔接者系统接口是最终表现。你只有打通全链路才能在遇到问题时高效定位。如果是新手建议先在一块闲置的开发板上做练习反复写入、回读、查看系统数据把整个流程做到闭眼能説。真正在生产中遇到问题时你最大的底气不是记得住某个命令而是明白每一步在做什么、为什么这么做。
返回列表