There is a long list of Ethernet related questions but none has a comprehensive answer covering all aspects. I'm generalizing your question in order to share my knowledge on this.
This is what you need to do in order to make Ethernet work on Android:
- Make sure OTG support is available
- Kernel must be built with Ethernet (and USB Ethernet) support
- Handle USB mode switch and kernel module loading (if applicable)
- Make Android framework do network configuration or do it manually
Note: Everything described below requires a rooted device, or at least the one with unlocked bootloader.
You should be familiar with commandline interface.
OTG SUPPORT
Your device must be able to operate in USB host mode.EthernetService
is started only if device supports feature USB host (android.hardware.usb.host
) or Ethernet (android.hardware.ethernet
). You may also need to use a powered USB hub if Android's USB power supply is not enough for connected device. Related question:
- Is there a definite way to know if my phone supports USB-OTG or not?
KERNEL CONFIGURATION
In order to use Ethernet over USB (adapters or modem-like devices) kernel must be built with CONFIG_USB_USBNET
and other configurations like USB_NET_CDCETHER
, USB_NET_HUAWEI_CDC_NCM
, USB_NET_CDC_MBIM
etc. depending on the type of connected device and the protocol it talks. Related questions:
- Where kernel modules are installed?
- Add a driver to kernel without flashing a new kernel
- Load an unsigned Kernel Module to signature enforcing Kernel
USB MODE SWITCH AND LOADING KERNEL MODULE
Many USB network devices are multi-mode or flip flop devices. They appear as USB Mass Storage device (also called ZeroCD mode) when inserted and need to be switched to Ethernet/PPP mode. USB_ModeSwitch is a Linux tool commonly used for this purpose. See some details here how it works. You need to build this tool for your device, or may download this binary for aarch64
. Get device database from here.
In order to automatically switch mode whenever the device is connected to Android, we need to listen to kernel USB uevents, either through hotplug helper or a userspace daemon (like udev
on Linux and ueventd
on Android). Additionally the kernel module can also be loaded/unloaded automatically. I'm defining an init
service here to achieve this, you can do it manually too.
Note: There is an Android app PPP Widget (by the developer of USB_ModeSwitch, I have no affiliation) which handles mode switching automatically and needs "no kernel driver modules, the 'driver' implementation is based on the Android USB host API". You might be interested in that too.
# /system/etc/init/custom.rc # kernel hotplug or uevent daemon service service cust.udevd /system/sbin/busybox uevent /system/sbin/udev.sh seclabel u:r:magisk:s0 disabled writepid /dev/cpuset/system-background/tasks # set kernel hotplug helper or start uevent daemon on boot on property:sys.boot_completed=1 #write /proc/sys/kernel/hotplug /system/sbin/udev.sh start cust.udevd
* In case of hotplug you need to define custom SELinux policies to let kernel make changes (see this answer for details).
#!/system/bin/sh # /system/sbin/udev.sh script is executed from kernel hotplug or uevent daemon # set PATH where you placed binaries export PATH=/system/bin # save log exec >>/dev/udev.log 2>&1 # don't execute multiple instances exec 200<>/dev/udev.lock flock 200 VID="12d1" # USB vendor ID of a Huawei devcie PID_UMS="1f01" # product ID in ZeroCD mode PID_ETH="14db" # product ID in Ethernet mode MODULE="cdc_ether" # kernel module for USB Ethernet IFACE="usb0" # Ethernet interface name matches() { [ -e "/sys/$DEVPATH/$1" ] || return 1 [ "$(cat "/sys/$DEVPATH/$1")" = "$2" ] || return 1 return 0 } # check if a new USB device is added or removed if [ "$SUBSYSTEM" = "usb" ] then # check if a USB device is added, then match VID and PID for mode switching # also device must belong to UMS class: https://www.usb.org/defined-class-codes#anchor_BaseClass08h if [ "$ACTION" = "add" ] && echo "$PRODUCT" | grep -q "$VID/$PID_UMS/" && matches bInterfaceClass 08 && matches bInterfaceNumber 00 then echo "Switching USB mode..." # USB mode switching of flip flop devices (USB modems, routers etc.) # usb_modeswitch_dispatcher needs /system/sbin/usb_modeswitch binary and configuration files in /etc # so you need to modify the hard-coded paths in source code as per your requirement usb_modeswitch_dispatcher --switch-mode "$(basename "$DEVPATH")" fi # match VID and PID for module loading # modprobe should be built with the hard-coded path to where you place modules e.g. /system/lib if echo "$PRODUCT" | grep -q "$VID/$PID_ETH/" then if [ "$ACTION" = "add" ] && ! grep -q "^$MODULE " /proc/modules then echo "Loading $MODULE module..." modprobe "$MODULE" elif [ "$ACTION" = "remove" ] && grep -q "^$MODULE " /proc/modules then echo "Removing $MODULE module..." modprobe -r "$MODULE" fi fi fi # on network interface event if [ "$SUBSYSTEM" = "net" ] && [ "$INTERFACE" = "$IFACE" ] then if [ "$ACTION" = "add" ] then echo "Starting cust.eth_config service..." #start cust.eth_config # uncomment if you want to do manual network configuration fi if [ "$ACTION" = "remove" ] then echo "Stopping cust.eth_config service..." #stop cust.eth_config # uncomment if you want to do manual network configuration fi fi
NETWORK CONFIGURATION
Android framework has a hard-coded name for Ethernet interface (default is eth0
, eth1
, ...). Whenever an Ethernet interface appears, its name is matched with the hard-coded value. Renaming interface afterwards doesn't work because only kernel provided interface name is tracked.
So you need to make this naming convention consistent between kernel and AOSP by modifying one of the both (if needed). Kernel provided name can be seen using ip
tool (as in your case it's usb0
). Use dumpsys
or de-compile /system/framework/framework-res.apk
using apktool to see the AOSP value.
~$ dumpsys ethernet ... Ethernet interface name filter: eth\d ...
As soon as an Ethernet interface appears, Android configures it automatically, NetworkMonitor
validates the connectivity and ConnectivityService
turns off WiFi and Mobile Data (if it's ON). Other services and components involved in configuration include UsbHostManager
, EthernetTracker
, EthernetNetworkFactory
, IpClient.eth0
, DhcpClient
, DnsManager
and Netd
.
EthernetService was added in Android 5. Before that AOSP was patched to make Ethernet work (e.g. see this and this). Still stock Android provides no GUI settings for Ethernet, but some custom ROM developers and OEMs do (e.g. see this). EthernetManager
class which is used to set and save manual IP configuration (to /data/misc/ethernet/ipconfig.txt
) is hidden. Default is to use a hard-coded configuration (see using dumpsys ethernet
under "IP Configurations:") or DHCP provided configuration.
MANUAL CONFIGURATION
You might want to do manual network configuration e.g. if:
- Android framework doesn't configure the Ethernet interface (on older devices or due to interface name inconsistency).
- You want to set static IP address or different DNS server.
- You want to use Ethernet along with WiFi or Mobile Data, or want to share internet among any of these.
But in this case Android's Java network stack remains down, so some apps depending on Android APIs may not behave normally. For related details see Connecting to WiFi via ADB Shell.
# /system/etc/init/custom.rc # Ethernet IP configuration service service cust.eth_config /system/sbin/eth_config.sh seclabel u:r:magisk:s0 disabled writepid /dev/cpuset/system-background/tasks # clear routing and DNS on property:init.svc.cust.eth_config=stopped exec u:r:magisk:s0 -- /system/sbin/eth_config.sh stop
#!/system/bin/sh # /system/sbin/eth_config.sh script is executed from eth_config init service # set PATH where you placed binaries export PATH=/system/bin IFACE=usb0 # Ethernet interface name DIR=/data/local/tmp/ethernet # temporary directory mkdir -p $DIR # save log exec >$DIR/eth_config.log 2>&1 if [ "$1" = stop ] then echo "Clearing configuration..." ip ru del lookup main ip r f table main ndc resolver setnetdns 0 '' 0.0.0.0 exit fi # destroy set network if any ndc network default set 0 # turn WiFi and Mobile Data off svc wifi disable svc data disable # set interfaces up ip link set dev lo up ip link set dev $IFACE up # Android doesn't use main table by default ip rule add lookup main # set IP, route and DNS manually here # or add any other IP/routing configuration # or run a minimal DHCP client as follows # create 'udhcpc' script <<-'SCRIPT' cat >$DIR/udhcpc_default.script #!/system/bin/sh case $1 in bound|renew) echo "Setting IP address, gateway route and DNS for $interface..." ip address f dev $interface ip route f table main ip address add $ip/$mask dev $interface ip route add default via $router dev $interface ndc resolver setnetdns 0 '' $dns ;; *) echo "Ignoring $1" ;; esac SCRIPT # start DHCP client to obtain IP from server chmod 0755 $DIR/udhcpc_default.script exec busybox udhcpc -v -f -i $IFACE -s $DIR/udhcpc_default.script
Do not forget to set proper permissions on .rc
file and shell scripts. Once setup, Ethernet works as soon as you connect USB adapter.