在 Android 设备上让 USB 网卡的「以太网共享」真正点亮:从排障到 RRO Overlay 的工程化落地

适用对象
已解锁 & 有 root/Magisk 设备、USB 千兆/2.5G 网卡(如 RTL8156/8156B/8156BG、AX88179A/B 等),插上后系统能识别为网卡但「设置 → 网络与互联网 → 热点与共享 → 以太网共享」始终灰色


背景:为什么“有网卡了,开关还是灰”?

大多数平板在插上 USB 网卡时,会通过 CDC-NCM 或厂商驱动(如 r8152)创建一个网络接口。问题在于:

  • 很多 ROM 只把 名字匹配 eth\d+ 的接口当作“以太网”。
    • 如果网卡被 CDC-NCM 驱动接管,接口常叫 usb0
    • UI 只认 eth0/eth1,于是灰着
  • 某些 ROM 还把 以太网共享功能开关config_tether_enable_ethernet)关掉了。

解决方向:不用折腾内核、也不强改驱动,直接用 RRO(Runtime Resource Overlay) 把系统资源改掉:

  • config_ethernet_iface_regex(“以太网接口命名的正则”)从 eth\d+ 扩到 (eth|usb|macsec)\d+(或至少 (eth|usb)\d+);
  • config_tether_enable_ethernet 设成 true
    重启后,系统会把 usb0 也当“以太网”,共享开关自然就亮了。

参考阅读:

备注:MACsecmacsec\d+)是二层链路加密(IEEE 802.1AE)的虚拟网口命名;是否需要无所谓,保留它不影响普通以太网共享。


先做最小自检

目的:确认驱动已加载接口存在链路通,避免因为网线没插好而误判为“系统不支持”。

下面的命令都是只读/安全的,适合先定位再决定怎么改。

# 1) 看网卡是不是走了 CDC-NCM(常见于 USB 2.5G/1G 网卡)
dmesg | grep -i -E 'cdc_ncm|r8152|usb'

# 2) 看系统当前把“以太网接口”匹配成什么(需要 root)
su -c 'cmd overlay lookup android android:string/config_ethernet_iface_regex'

# 3) 列出所有网口 + 链路状态(carrier=1 才算真的插上对端)
ls -l /sys/class/net
for n in /sys/class/net/*; do
  b=$(basename "$n")
  printf "%-10s carrier=%s  dev=%s\n" "$b" \
    "$(cat $n/carrier 2>/dev/null || echo '?')" \
    "$(readlink -f $n/device 2>/dev/null || echo '-')"
done

# 4) 确认 USB 速率(尽量是 5000,代表 USB 3.x SuperSpeed)
BUS=2-1   # 用 dmesg 里看到的总线号替换
cat /sys/bus/usb/devices/$BUS/speed

典型结论

  • dmesg 里能看到 cdc_ncm … usb0
  • overlay lookupeth\d
  • /sys/class/netusb0carrier=1,但设置里“以太网共享”仍灰。
    问题不在驱动,而在系统“接口名正则”与共享开关。r8152 与 CDC-NCM 是两条路,是否可用取决于设备固件枚举形态与内核配置。参考:r8152 驱动资料、CDC 文档。) GitHub Linux内核文档

总览:三条可选路线(由易到难)

  1. 静态 RRO Overlay(推荐)
    • 在 PC 上用 aapt2 生成一个极小的 overlay APK,覆盖两个资源;
    • 做成 Magisk 模块挂到 /product/overlay/
    • 重启后官方 UI 直接可用。
    • 稳定、通用、无需改内核/驱动。
  2. 动态覆盖 / DeviceConfig(看 ROM 是否放行)
    • cmd overlay fabricate(运行时覆盖)或 device_config put(运行时参数)
    • 很多厂商 ROM 禁用了 shell 写入,容易失败,不建议投入太多时间。
    • 仅作为补充尝试。
  3. 不依赖 UI 的手工共享(临时应急)
    • iptables + ip addr + busybox udhcpd 做 NAT/DHCP;
    • 立刻可用,但不是长久解;需要配套清理脚本,以免“搞崩网”。

方案 A(推荐):PC 做一个静态 RRO Overlay + Magisk 模块(一步到位)

思路:和 Treble 的 vendor_hardware_overlay 是同一种 RRO(Runtime Resource Overlay)机制,只不过我们把 overlay APK 放到 /product/overlay(通过 Magisk 挂载,不动只读分区)。系统在开机OverlayManagerService + idmap 自动加载。

0) 前提

  • 设备已 root(Magisk)。
  • PC 安装了 Android SDK Build-Tools(含 aapt2)和 adb

1) 准备资源文件

res/values/config.xml —— 扩大接口正则 + 打开以太网共享:

<resources>
  <string name="config_ethernet_iface_regex">(eth|usb|macsec)\\d+</string>
  <bool name="config_tether_enable_ethernet">true</bool>
</resources>

(eth|usb)\\d+ 也能满足大多数场景;保留 macsec 与 AOSP 示例一致。参考示例见 AOSP 代码搜索与 cuttlefish overlay。
(AOSP 默认值可在 frameworks/base/core/res/res/values/config.xml 里看到,以 eth\\d 为主。)
参考:
– AOSP config_ethernet_iface_regex(默认值与注释)
– Automotive overlay 示例(含 macsec
– 官方 RRO 机制说明
链接:
cs.android.com: config.xml(默认值)
cs.android.com: 示例 overlay(含 macsec)
source.android.com: RRO 文档

AndroidManifest.xml —— 标准 RRO 清单:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="me.overlay.eth_ethernet" android:versionCode="1" android:versionName="1.0">
  <application android:hasCode="false"/>
  <overlay android:targetPackage="android"
           android:targetName="android"
           android:isStatic="true"
           android:priority="1"/>
</manifest>

2) 用 aapt2 编译 Overlay APK(PC)

# 拉系统 framework-res 以便链接
adb root
adb pull /system/framework/framework-res.apk .

# 生成并编译资源
mkdir -p eth-overlay/res/values
# 将上面的 config.xml 和 AndroidManifest.xml 放入对应路径

AAPT2="$ANDROID_HOME/build-tools/34.0.0/aapt2"   # 按你的实际路径调整
"$AAPT2" compile -o eth-overlay/compiled.flata eth-overlay/res/values/config.xml
"$AAPT2" link -o EthEthernetOverlay.apk \
  -I framework-res.apk \
  --manifest eth-overlay/AndroidManifest.xml \
  eth-overlay/compiled.flata

aapt2 来自 Android SDK Build-Tools;任意 30+ 版本都可。官方 RRO 文档与排障文档也说明了 overlay 的装载流程与限制点。

3) 打包成 Magisk 模块并安装

mkdir -p eth_tether_overlay/system/product/overlay
cat > eth_tether_overlay/module.prop <<'EOF'
id=eth_tether_overlay
name=Ethernet Tether Overlay
version=1.0
versionCode=1
author=you
description=Enable Ethernet tethering + widen iface regex (eth|usb|macsec).
EOF

mv EthEthernetOverlay.apk eth_tether_overlay/system/product/overlay/
touch eth_tether_overlay/auto_mount

( cd eth_tether_overlay && zip -r ../eth_tether_overlay.zip . )
adb push eth_tether_overlay.zip /sdcard/
adb shell su -c 'magisk --install-module /sdcard/eth_tether_overlay.zip'
adb shell su -c 'svc power reboot'

4) 验证

# 设备重启后,插上 USB 网卡,确认链路对端通电(carrier=1)
adb shell su -c 'cat /sys/class/net/usb0/carrier || cat /sys/class/net/eth0/carrier'

# 设置 → 网络与互联网 → 热点与共享 → 以太网共享 现在应可开启

方案 B(补充):动态覆盖 / 运行时参数(可能被 ROM 禁用)

有的 Android 版本支持 cmd overlay fabricate 运行时注册覆盖;也有 ROM 会从 DeviceConfig 读取这些键:

android:string/config_ethernet_iface_regex
android:bool/config_tether_enable_ethernet

但现实里大量厂商固件会:

  • cmd overlay fabricate 加限制(各种语法都报错/commit failed);
  • device_config put 加限制(shell 调用 Failed transaction)。

建议:只做轻量尝试即可,遇到墙就别纠缠,直接上 静态 RRO

参考:


方案 C(应急):不靠 UI,手工共享(NAT + DHCP)

当你现在就要能用时,可以先用命令行把以太网“桥接”出去。原理:给下行口配网段 → 打开内核转发 → iptables 做 MASQUERADE → 用 BusyBox udhcpd 发地址。

下行口(LAN):usb0/eth0(看实际)
上行口(WAN):wlan0(Wi-Fi)或 rmnet_data0(移动数据)

su
IF=usb0      # 或 eth0
UP=wlan0     # 或 rmnet_data0

ip link set $IF up
ip addr add 192.168.88.1/24 dev $IF 2>/dev/null
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o $UP -j MASQUERADE
iptables -A FORWARD -i $UP -o $IF -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i $IF -o $UP -j ACCEPT

# DHCP(若已装 BusyBox)
cat > /data/local/tmp/udhcpd-$IF.conf <<EOF
start   192.168.88.10
end     192.168.88.100
interface   $IF
option  subnet  255.255.255.0
option  router  192.168.88.1
option  dns     1.1.1.1 8.8.8.8
lease   3600
EOF
busybox udhcpd -f /data/local/tmp/udhcpd-$IF.conf &

停止/清理(很重要)

su
pkill udhcpd 2>/dev/null || true
iptables -t nat -D POSTROUTING -o $UP -j MASQUERADE 2>/dev/null || true
iptables -D FORWARD -i $UP -o $IF -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
iptables -D FORWARD -i $IF -o $UP -j ACCEPT 2>/dev/null || true
ip addr flush dev $IF 2>/dev/null || true
echo 0 > /proc/sys/net/ipv4/ip_forward

工程化小结

  • 先验判断
    • dmesg 看到 CDC-NCM → usb0,UI 灰:十有八九是 config_ethernet_iface_regex 过窄
    • carrier=1 是 UI 可点的前置条件;对端设备必须通电、线要通。
    • 不要预设“必须是 r8152 才行”,很多平板只暴露 CDC-NCM,r8152 根本绑不上。
  • 优先方案
    • 直接做 静态 RRO overlay/product/overlay,Magisk 模块挂载),把
      config_ethernet_iface_regex = (eth|usb|macsec)\d+
      config_tether_enable_ethernet = true
    • 这是与 Treble 的 vendor_hardware_overlay 同一原理,只是放在更易维护的分区。
  • 备选方案
    • ROM 放行时再尝试 cmd overlay fabricate / device_config put
    • 不放行就别折腾时间。
  • 应急/调试
    • iptables + udhcpd 随时救急,但要配套清理脚本,别把系统网络环境“搞崩”。

常见问题(FAQ)

Q1:为什么有些 USB 网卡“插上就能共享”,有些不行?
A:能“即插即用”的,多半枚举成 ethX(走 r8152 或厂商栈),正则匹配直接命中;而枚举为 usb0(CDC-NCM)的,就被默认正则漏掉。把正则扩到包含 usb 即可。([Android代码搜索][2])

Q2:我能不能强行把 CDC-NCM 的 usb0 改名为 eth0 就算了?
A:可以短期应急(ip link set usb0 name eth0),但风险是系统升级/重枚举会变,且有些 ROM 还检查其他条件。从系统资源层把正则改对,才是稳定策略。([Android Open Source Project][6])

Q3:cmd overlay fabricatedevice_config put 为啥经常失败?
A:它们受 ROM 策略限制。动态覆盖是“运行时注册”的临时包,很多厂商关闭了 shell 侧;device_config 也常被忽略。静态 RRO是 Treble 官方路径,最稳。([Android Open Source Project][1])

Q4:macsec 必须加吗?
A:不是必须。(eth|usb)\d+ 足够大多数平板;加上 macsec 是向官方示例对齐,也不影响功能。([1.ieee802.org][7])


如果你已具备 root + Magisk 环境,上面的 Overlay 模块就是“一劳永逸”的做法;既不需要修改内核,也不用一直手动 NAT。希望这篇记录能帮到正在折腾 USB 网卡以太网共享的 Android 平板同学。

参考链接

* 本文包含AI生成信息。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Back to Top