OpenHarmony 开发板摆脱 USB 线:开机自动监听 hdc TCP xxx(例如8710) + 网口静态 IP 配置实录
一、痛点
调 OpenHarmony 开发板的同学应该都熟悉这个流程:
- 插 USB 线;
hdc list targets确认设备;- 手动执行
hdc tmode port 8710,让 hdcd 重启并切换到 TCP 监听模式; - 之后才能
hdc tconn <板子IP>:8710走网络连接。
麻烦在于:tmode 切换是一次性的,板子一重启就打回原形,每次都得插 USB 重新来一遍。板子装在机壳里、放在测试架上、或者要交给别的同事用的时候,来回插线非常折磨。
理想状态是:板子上电、网线一插,PC 直接 hdc tconn 就能连上,USB 线只在刷机和首次配置时才需要。
本文记录我在这块板子上的完整配置过程,包括中途踩的坑和一个重要发现------很多版本的 OpenHarmony 根本不需要自启脚本,两条 param 命令就够了。
环境说明:OpenHarmony 标准系统,hdcd 版本
Ver: 3.2.0c(hdc shell "param get const.hdc.version"可查)。不同版本的 hdcd 行为可能不同,动手前建议先按本文第六节确认你的镜像支持。
二、先排雷:网上流传的 init.rc 自启方案,在标准系统上是无效的
搜"OpenHarmony hdc 开机自动 TCP"很容易搜到这样的方案(我一开始也打算这么做):
service hdc_tcp_start /system/bin/sh -c "sleep 3; /system/bin/hdc tmode port 8710"
class: late
user: root
group: root
oneshot
on boot
start hdc_tcp_start
这是 Android init 的 .rc 语法。OpenHarmony 标准系统的 init 进程只解析 JSON 格式的 .cfg 文件 (也就是 /system/etc/init/ 下那一大堆 xxx.cfg)。把上面这种 rc 文件放进板子,不会报错、不会有任何提示------它就是被静默忽略。你只会以为"服务起来了但没生效",然后在错误的方向上浪费一下午。
正确的 OH 服务配置长这样(供对比,hdc_tcp.cfg):
json
{
"services": [
{
"name": "hdc_tcp_start",
"path": ["/system/bin/sh", "/system/bin/hdc_tcp_start.sh"],
"uid": "root",
"gid": ["root"],
"once": 1,
"seclabel": "u:r:shell:s0"
}
],
"jobs": [
{
"name": "boot",
"cmds": [ "start hdc_tcp_start" ]
}
]
}
这套方案需要 remount /system 为可写、推两个文件上去,还有 sleep 等网卡的玄学时序问题。
但幸运的是,往下看,你大概率一个文件都不用推。
三、翻 hdcd 自己的配置,发现新大陆
配置之前先看系统里现成的东西(这个习惯能省很多事):
bash
hdc shell "cat /system/etc/init/hdcd.cfg"
hdcd.cfg 是 hdcd 守护进程自己的 init 配置,里面除了服务定义,还有一组 param watcher(参数监视)job,关键片段:
json
{
"name" : "param:persist.hdc.mode.tcp=disable && param:persist.hdc.mode.usb=disable",
"condition" : "persist.hdc.mode.tcp=disable && persist.hdc.mode.usb=disable",
"cmds" : [ "stop hdcd" ]
},
{
"name" : "param:persist.hdc.mode.tcp=enable && param:persist.hdc.mode.usb=disable",
"condition" : "persist.hdc.mode.tcp=enable && persist.hdc.mode.usb=disable",
"cmds" : [ "reset hdcd" ]
},
{
"name" : "param:persist.hdc.mode.tcp=enable && param:persist.hdc.mode.usb=enable",
"condition" : "persist.hdc.mode.tcp=enable && persist.hdc.mode.usb=enable",
"cmds" : [ "reset hdcd" ]
}
翻译一下:hdcd 原生支持三个持久化通道参数,任何一个变化都会自动重启 hdcd 使其生效:
| 参数 | 含义 |
|---|---|
persist.hdc.mode.usb |
USB 通道开关 |
persist.hdc.mode.tcp |
TCP 通道开关 |
persist.hdc.mode.uart |
串口通道开关 |
persist.hdc.port |
TCP 监听端口 |
persist. 前缀的参数存在 /data/param,重启不丢。也就是说"开机自动进 TCP 模式"是 hdcd 的原生能力,只需要把参数设上。
再确认当前状态:
bash
hdc shell "param get persist.hdc.mode.tcp" # 我的板子:disable
hdc shell "param get persist.hdc.mode.usb" # 我的板子:enable
hdc shell "param get persist.hdc.port" # 注意,见下一节
四、两条命令搞定开机自启(核心)
bash
hdc shell "param set persist.hdc.mode.tcp enable"
hdc shell "param set persist.hdc.port 8710"
- 第一条:开机自动进入 TCP 监听。执行瞬间 param watcher 就会触发
reset hdcd,USB 会闪断几秒然后自己恢复,属于正常现象。 - 第二条:固定监听端口为 8710。
为什么还要显式设端口?------一个差点漏掉的坑
设置 tcp=enable 之后我用 netstat 检查,发现 8710 端口上只有 UDP,没有 TCP LISTEN:
$ hdc shell "netstat -an | grep 8710"
udp 0 0 0.0.0.0:8710 0.0.0.0:*
一度以为方案失败了。后来 param get | grep hdc 翻参数列表才发现:
persist.hdc.port = 35129
真相:8710 端口上的 UDP 是 hdcd 的设备发现广播(同网段 hdc list targets 能自动扫到就是靠它),而 TCP 真正监听的端口由 persist.hdc.port 决定 ------我的板子上这个参数残留着 35129:
$ hdc shell "netstat -an | grep 35129"
tcp 0 0 0.0.0.0:35129 0.0.0.0:* LISTEN
TCP 服务器早就开好了,只是不开在 8710。把 persist.hdc.port 设成 8710(改端口参数不会立刻触发重启,重启后生效),问题解决。
顺带一提:如果
param get persist.hdc.mode.tcp报errNum 106(参数不存在),说明你的镜像 hdcd 版本较老,不支持参数方式,那就只能走第二节的自启 cfg 方案了。
五、网口静态 IP:netmanager 按网卡存文件
开机 IP 这块也不需要脚本。OpenHarmony 的 netmanager(以太网服务)为每张网卡维护一个独立的配置文件:
/data/service/el1/public/netmanager/ethernet/eth0
内容是 key=value 格式,我的板子出厂时是:
DEVICE=eth0
BOOTPROTO=STATIC
IPADDR=192.168.1.1
NETMASK=255.255.255.0
GATEWAY=
ROUTE=192.168.1.1
ROUTE_NETMASK=0.0.0.0
DNS=
PROXY_HOST=
PROXY_PORT=0
PROXY_EXCLUSIONS=
几个字段的含义:
| 字段 | 说明 |
|---|---|
BOOTPROTO |
STATIC 静态 / DHCP 自动获取 |
IPADDR / NETMASK |
板子的 IP 和掩码 |
GATEWAY |
默认网关 |
ROUTE + ROUTE_NETMASK |
静态路由,一般填网关 + 0.0.0.0 |
DNS |
DNS 服务器,一般填网关 |
我的板子出厂 IP 是 192.168.1.1------恰好和常见路由器网关冲突,正好一起改掉。目标:板子 192.168.1.2,掩码 255.255.255.0,网关 192.168.1.1。
写入方法(USB 连着板子,直接一条命令)
bash
hdc shell "printf 'DEVICE=eth0\nBOOTPROTO=STATIC\nIPADDR=192.168.1.2\nNETMASK=255.255.255.0\nGATEWAY=192.168.1.1\nROUTE=192.168.1.1\nROUTE_NETMASK=0.0.0.0\nDNS=192.168.1.1\nPROXY_HOST=\nPROXY_PORT=0\nPROXY_EXCLUSIONS=\n' > /data/service/el1/public/netmanager/ethernet/eth0"
再把属主和权限改回和原文件一致(netmanager 以 uid 1099 运行):
bash
hdc shell "chown 1099:1099 /data/service/el1/public/netmanager/ethernet/eth0 && chmod 660 /data/service/el1/public/netmanager/ethernet/eth0"
如果不想敲命令:很多量产板预装了"以太网配置"应用,在里面改 IP,写的就是这个文件。二选一。
两个必须知道的特性
- 网线没插的时候,eth0 就是没有 IP,这不是配置失败。 netmanager 在链路 UP 时才应用配置。插上网线几秒内 IP 自动出现。我第一次重启后验证差点误判,后来
cat /sys/class/net/eth0/carrier看到0(无载波)才反应过来网线是拔着的。 - DHCP 和 STATIC 的行为差异在这里也适用:
BOOTPROTO=DHCP时由 DHCP 服务端分配,配置文件里的 IPADDR 等字段不生效。
六、重启,逐项验证
bash
hdc shell reboot
等系统起来(USB 目标会自己回来,30 秒左右),逐项检查:
bash
# 1. 参数持久化
hdc shell "param get persist.hdc.mode.tcp" # → enable
hdc shell "param get persist.hdc.port" # → 8710
# 2. 开机自动 TCP 监听(核心目标)
hdc shell "netstat -an | grep LISTEN | grep 8710"
# → tcp 0 0 0.0.0.0:8710 0.0.0.0:* LISTEN
# 3. 网口 IP(前提:网线已插)
hdc shell "ifconfig eth0"
# → inet addr:192.168.1.2 Bcast:192.168.1.255 Mask:255.255.255.0
# 4. PC 侧连接(PC 网卡必须先配到 192.168.1.x,比如 192.168.1.100/24)
hdc tconn 192.168.1.2:8710
hdc list targets # 列表出现 192.168.1.2:8710 即成功
之后所有 hdc shell / file send / install 命令照常使用。板子或 PC 重启后,重新 tconn 一次即可。
七、踩坑记录
都是过程中真实撞到的,列出来帮后来人省时间:
hdc file send失败时返回码仍然是 0。 我第一次推文件时本地路径写错,hdc 打印了[Fail]Error opening file但&&链后面的命令照样执行了。推完文件必须回读验证 (cat/grep一下),不能信任命令退出码。- Git Bash 下 hdc 的板端路径会被 MSYS 自动转换 ,
/data/...被改写成D:/Program Files/Git/data/...。加前缀解决:MSYS_NO_PATHCONV=1 hdc file send ...。用 cmd/PowerShell 没这个问题。 - toybox 的 netstat 不支持
-o参数 (Android 上常用的netstat -ano会报错),用netstat -an就够。 [Fail]ExecuteCommand need connect-key?有两种成因 :一是 USB 和 TCP 两个目标同时在线,hdc 不知道操作哪个,用hdc -t <目标> <命令>指定;二是设备瞬断(我遇到过两次,第二次直接掉了),重插 USB 即可。- 查 hdcd 行为看 hilog ,tag 是
C02d13/HDC_LOG:hdc shell "hilog -x | grep -iE 'hdcd'",参数是否生效、daemon 有没有重启,日志里一目了然。
八、稳定性与兜底
- 建议保留 USB 通道 (
persist.hdc.mode.usb保持默认enable)。TCP + USB 可以同时开,网络出问题时插 USB 线还能救。真要纯 TCP(param set persist.hdc.mode.usb disable)请三思------一旦网络不通,就只能重刷了。 - 所有配置都在
/data分区:恢复出厂或重刷镜像会全部丢失。把第四、五节的命令存成一个文本,重刷后照着敲一遍(或做成脚本)就恢复了。 - 一块板子同时只服务一个 hdc 客户端,第二个人连上来会顶掉第一个,团队共用时注意错开。
- 判断板子是否"网络就绪",别只看能不能 ping 通板子,
hdc shell "netstat -an | grep LISTEN"看到 8710 才算服务真正起来了。
九、命令速查
新板子从零配好(USB 连接状态下,依次执行):
bash
# 前置检查:镜像是否支持参数方式(读到值即可,disable 也算支持)
hdc shell "param get persist.hdc.mode.tcp"
# 1. 开机自动 TCP 监听,端口 8710
hdc shell "param set persist.hdc.mode.tcp enable"
hdc shell "param set persist.hdc.port 8710"
# 2. 网口静态 IP:192.168.1.2/24,网关 192.168.1.1
hdc shell "printf 'DEVICE=eth0\nBOOTPROTO=STATIC\nIPADDR=192.168.1.2\nNETMASK=255.255.255.0\nGATEWAY=192.168.1.1\nROUTE=192.168.1.1\nROUTE_NETMASK=0.0.0.0\nDNS=192.168.1.1\nPROXY_HOST=\nPROXY_PORT=0\nPROXY_EXCLUSIONS=\n' > /data/service/el1/public/netmanager/ethernet/eth0"
hdc shell "chown 1099:1099 /data/service/el1/public/netmanager/ethernet/eth0 && chmod 660 /data/service/el1/public/netmanager/ethernet/eth0"
# 3. 重启生效
hdc shell reboot
# 4. PC 侧(网卡先配到 192.168.1.x)
hdc tconn 192.168.1.2:8710
十、总结
hdc tmode是一次性切换,这个"印象"让很多人(包括我)以为必须写开机脚本。实际上新一点的 hdcd 用persist.hdc.mode.tcp+persist.hdc.port两个参数就能实现持久 TCP 监听,零文件改动、重启不丢。- 网上流传的 Android 风格 init.rc 方案在 OpenHarmony 标准系统上会被静默忽略,OH 的 init 只认 JSON cfg------动手前先看
/system/etc/init/里系统自己是怎么写的。 - 网口静态 IP 就是 netmanager 的一个 key=value 小文件,按网卡名存放在
/data/service/el1/public/netmanager/ethernet/下。 - 排查问题多看日志(
hilog)和多翻系统自带配置(/system/etc/init/*.cfg、param get),答案往往系统里早就写好了。