Android系统中如何添加USB网络共享

本文介绍如何在Android系统中配置USB网络共享功能,包括内核配置、frameworks配置和服务启动等步骤,实现通过USB接口共享网络。

Android系统中如何添加USB网络共享

类别

需求

索引类别

USB网络共享

问题描述

平台是RT1296,在Android系统中已经有支持USB网络共享,但相应的产品系统中还未开启USB网络共享,那么这个时候就需要添加USB网络共享的一些配置,使得产品支持此功能。(以下是个人的一些理解,如有错误,请各位大佬多多指教)

代码关联

对应的代码修改部分如下:

①对应内核中添加配置(系统中添加USB网络驱动)

@@ -837,3 +837,6 @@ CONFIG_ZRAM=y
 CONFIG_ZRAM_LZ4_COMPRESS=y
 CONFIG_ZSMALLOC=y
 # CONFIG_ZSMALLOC_STAT is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_IPHETH=y
+CONFIG_USB_NET_RNDIS_HOST=y

②在init.rc中增加两个针对usb0的配置服务,才能让framework配置得了usb0网卡(服务是是USB网络共享的核心)

@@ -134,3 +134,16 @@ on property:persist.iso.state=unmounted
#在开机启动的时候会发送一个bootcomplete广播,接收广播后启动scdetect、rootshellservice
 on property:dev.bootcomplete=1
     start scdetect
     start rootshellservice
#启动usb网络分配dhcp
+service dhcpcd_usb0 /system/bin/dhcpcd -ABDKL -f/system/etc/dhcpcd/dhcpcd.conf
+    class main
+    disabled
+    oneshot
+    seclabel u:r:dhcp:s0
#启动usb网络分配ip
+service iprenew_usb0 /system/bin/dhcpcd -n
+    class main
+    disabled
+    oneshot
+    seclabel u:r:dhcp:s0

③对应Android源码,frameworks中添加配置(这边主要是讲述网络是如何启动的,是选择那个网络)

/frameworks/base/core/res/res/values/config.xml 
     <bool name="config_enableMonitorInputSource">true</bool>
-    <string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
+    <string translatable="false" name="config_ethernet_iface_regex">eth\\d|usb\\d</string>

上面的作用是提供两种网络的方式,一种是以太网络,一种是走usb共享

    /frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
     public synchronized void start(Context context, Handler target) {
        Log.i(TAG, "monitoring start");
        // The services we use.
        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
        mNMService = INetworkManagementService.Stub.asInterface(b);
        mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE);

        //在这里就获取上面设定config_ethernet_iface_regex的值
        mIfaceMatch = context.getResources().getString(
                com.android.internal.R.string.config_ethernet_iface_regex);

        // Create and register our NetworkFactory.
        mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper());
        mFactory.setCapabilityFilter(mNetworkCapabilities);
        mFactory.setScoreFilter(-1); // this set high when we have an iface
        mFactory.register();

        mContext = context;

        // Start tracking interface change events.
        mInterfaceObserver = new InterfaceObserver();
        try {
            mNMService.registerObserver(mInterfaceObserver);
        } catch (RemoteException e) {
            Log.e(TAG, "Could not register InterfaceObserver " + e);
        }

        // If an Ethernet interface is already connected, start tracking that.
        // Otherwise, the first Ethernet interface to appear will be tracked.
        try {
            final String[] ifaces = mNMService.listInterfaces();
            for (String iface : ifaces) {
                synchronized(this) {
                    //在这里判断是采用哪个网络
                    if (maybeTrackInterface(iface)) { 
                        // We have our interface. Track it.
                        // Note: if the interface already has link (e.g., if we
                        // crashed and got restarted while it was running),
                        // we need to fake a link up notification so we start
                        // configuring it. Since we're already holding the lock,
                        // any real link up/down notification will only arrive
                        // after we've done this.
                        if (mNMService.getInterfaceConfig(iface).hasFlag("running")) {
                            updateInterfaceState(iface, true);
                        }
                        break;
                    }
                }
            }
            *
            *
            *
            *
        }
    }

    //在这边可以选择是走那个网络是eth还是usb         
    private boolean maybeTrackInterface(String iface) {
        // If we don't already have an interface, and if this interface matches
        // our regex, start tracking it.
        if (!iface.matches(mIfaceMatch) || isTrackingInterface())
            return false;

        if(UbusRpc.isOpenWrt() && !UbusRpc.isOttWifi()){
            if(!iface.equals("eth9"))
                return false;
        } else if(!iface.equals(SystemProperties.get("net.eth.iface", "eth0"))){
            return false;
        }

        Log.d(TAG, "Started tracking interface " + iface);
        setInterfaceUp(iface);
        return true;
    }

④最后在设置一个属性值:setprop net.eth.iface usb0/eth0 (usb0强制网络走手机USB网络共享)

应用层发送一个广播,这样就可以自由的切换是使用USB还是以太网。

 Intent intent = new Intent("rtk.intent.action.SET_ETH_IFACE");
 intent.putExtra("EXTRA_ETH_IFACE"," usb0/eth0 ");
 sendBroadcast(intent);

对应frameworks的接收应用发送的广播代码:

/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java

private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver(){
 @Override
 public void onReceive(Context context, Intent intent) {
 String action = intent.getAction();
 	if("rtk.intent.action.SET_ETH_IFACE".equals(action)){
 			String iface = intent.getStringExtra("EXTRA_ETH_IFACE");
	 		if(iface==null) iface="eth0";
 			SystemProperties.set("net.eth.iface", iface);
 			Log.i(TAG, "restart EthernetNetworkFactory");
 			enforceConnectivityInternalPermission();
 			synchronized (mIpConfiguration) {
 				mTracker.stop(); 
 				//重启网络,即调用第③步的start
 				mTracker.start(mContext, mHandler); 
			}
 		}
 	}
 };

如果没有效果,请排查一下/sys/class/net/中是否有新生成一个usb0的节点,如果没有生成的话排查第①第②步是否正常开启。

知识拓展

参考资料:https://blog.youkuaiyun.com/tankai19880619/article/details/44559419?_t=t

改进建议

若有错误请指正,悉心接受大佬的指点 谢谢 ! v

工作记录。。。。。

<think> 我们讨论的是Android 13系统USB网络共享USB Tethering)分配IP地址的代码实现流程。根据之前的信息,我们知道Android设备在USB网络共享模式下会作为DHCP服务器,为连接的客户端设备分配IP地址(通常是192.168.42.0/24子网)。 代码实现流程主要涉及Android网络服务(netd)和DHCP服务器进程(dnsmasq或内部DHCP服务)。在Android中,USB网络共享相关的代码位于frameworks/base/services/core/java/com/android/server/connectivity/ 和 system/netd 目录下。 以下是大致的代码流程: 1. **启用USB网络共享**: 当用户在设置中启用USB网络共享时,会调用Tethering服务的`startTethering`方法。该方法位于`frameworks/base/services/core/java/com/android/server/connectivity/Tethering.java`。 ```java // Tethering.java public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) { // ... 验证权限和状态 enableTetheringInternal(type, true, receiver); } ``` 2. **配置USB网络接口**: 当USB网络共享启用时,系统会创建usb0网络接口(或者类似,具体名称可能因设备而异)。这一步通常由netd(网络守护进程)处理。netd会通过`NetworkManagementService`来设置接口。 ```java // Tethering.java private boolean configureUsbIface(boolean enabled) { final String iface = mUsbIface; try { if (enabled) { // 设置接口为UP状态 mNetd.interfaceSetEnable(iface, true); // 设置IP地址和子网掩码(通常为192.168.42.1/24) mNetd.interfaceSetCfg(new InterfaceConfigurationParcel(iface, "192.168.42.1", 24, ...)); // ... 其他配置 } else { // 关闭接口 } } catch (RemoteException | ServiceSpecificException e) { // 处理异常 } return true; } ``` 3. **启动DHCP服务器**: 在Android中,DHCP服务器功能通常由`dnsmasq`提供(但注意,在较新的Android版本中,有时会使用内置的DHCP服务器)。启动DHCP服务器的命令由Tethering服务通过Netd发送。 在`Tethering`类中,会调用`startDhcp`方法(具体实现可能在不同版本有差异)。在Android 13中,可能会启动一个内置的DHCP服务器(如`tethering`模块中的DhcpServer)而不是dnsmasq。 ```java // 在Tethering.java中,启动DHCP服务 private void startDhcp() { DhcpServerParameters params = new DhcpServerParameters.Builder() .setDefaultTransmitPackets() // 设置默认参数 .setIpRange("192.168.42.2", "192.168.42.254") .setSubnetMask("255.255.255.0") .setDnsServers(...) // 设置DNS,通常为网关IP(192.168.42.1) .setLeaseTime(3600) // 租约时间 .build(); mDhcpServer = new DhcpServer(mContext, params); mDhcpServer.start(); } ``` 注意:实际代码中,Android可能使用`dnsmasq`作为DHCP服务器,通过启动一个dnsmasq进程并传递参数。但根据版本,也可能使用自带的DhcpServer(在Android 11及以后,Google逐步用自带的DhcpServer替代dnsmasq)。在Android 13中,Tethering模块使用内置的DhcpServer。 4. **DHCP服务器实现**: 内置的DhcpServer代码位于`frameworks/base/services/core/java/com/android/server/dhcp`。主要类包括`DhcpServer`和`DhcpPacket`等。当DhcpServer启动后,它会监听DHCP请求(UDP端口67)并处理DHCPDISCOVER、DHCPREQUEST等消息,分配IP地址。 ```java // DhcpServer.java public void start() { mThread = new Thread(() -> { while (true) { // 接收DHCP包 DhcpPacket packet = receivePacket(); // 处理包 processPacket(packet); } }); mThread.start(); } private void processPacket(DhcpPacket packet) { switch (packet.getType()) { case DHCPDISCOVER: // 分配IP地址 Inet4Address clientIp = allocateIpAddress(packet.getClientMac()); // 构造DHCPOFFER包并发送 sendOfferPacket(packet, clientIp); break; case DHCPREQUEST: // 确认分配,发送DHCPACK sendAckPacket(packet, clientIp); break; // ... 其他类型 } } ``` 5. **防火墙和NAT配置**: 除了分配IP地址,还需要配置NAT(网络地址转换)以便客户端设备可以访问互联网。这通常通过iptables规则实现。在Tethering中,会配置nat表的相关规则。 ```java // Tethering.java private void setUsbTethering(boolean enable) { // ... 配置NAT if (enable) { mNetd.tetherAddForward(mUsbIface, "rmnet_data0"); // 假设rmnet_data0是移动数据接口 // 设置转发和伪装(MASQUERADE) mNetd.ipfwdEnableForwarding("tethering"); mNetd.tetherStart(new TetherConfigParcel(true, new String[] {mUsbIface}, ...)); } else { // 清除规则 } } ``` 具体的iptables规则由netd执行,例如: ```bash iptables -t nat -A POSTROUTING -o rmnet_data0 -j MASQUERADE ``` 6. **客户端获取IP地址**: 客户端设备(如电脑或路由器)会发起DHCP请求,DhcpServer响应并分配IP地址。客户端配置的默认网关就是Android设备的usb0接口的IP(192.168.42.1)。 总结流程: 1. 用户启用USB网络共享。 2. Tethering服务配置usb0接口,设置IP地址(192.168.42.1/24)并启用接口。 3. 启动内置DhcpServer(或dnsmasq),监听usb0接口,准备分配IP地址。 4. 配置NAT规则,允许客户端通过移动数据接口访问互联网。 5. 客户端通过DHCP请求获取IP地址(如192.168.42.2),然后通过Android设备的网关上网。 注意:以上代码流程基于Android源代码的分析,实际实现细节可能因版本和设备而异。在Android 13中,部分实现可能有所调整,但整体架构保持一致。 相关问题: 1. Android 13中DhcpServer的实现与dnsmasq相比有哪些优势? 2. USB网络共享的NAT配置在Android系统中是如何具体实现的? 3. 如何在Android 13中调试USB网络共享的DHCP服务? </think> ### Android 13 USB网络共享IP分配代码实现流程 在Android 13系统中,USB网络共享的IP地址分配主要通过三个核心模块协同实现:**Tethering服务**、**DHCP服务器**和**网络接口管理**。以下是详细的代码实现流程(基于AOSP源码分析): #### 1. **Tethering服务初始化** 当用户启用USB网络共享时,`TetheringService`(位于`frameworks/base/services/core/java/com/android/server/connectivity/`)触发以下流程: ```java // Tethering.java public void startTethering(int type) { if (type == TETHERING_USB) { mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED); updateUsbState(true); // 激活USB共享状态 } } ``` 该方法通过状态机`TetherMasterSM`通知网络子系统准备USB共享[^1]。 --- #### 2. **USB接口配置** 网络守护进程`netd`(位于`system/netd/`)创建虚拟接口并分配网关IP: ```cpp // NetdNativeService.cpp status_t NetdNativeService::tetherInterface(const string& iface) { setInterfaceAddress(iface, "192.168.42.1/24"); // 固定网关IP setInterfaceEnable(iface, true); // 激活接口 } ``` 此处硬编码配置网关IP为`$192.168.42.1$`,子网掩码`$255.255.255.0$/24$`[^1]。 --- #### 3. **DHCP服务器启动** Android使用内置的`DhcpServer`(位于`frameworks/base/services/core/java/com/android/server/dhcp/`): ```java // DhcpServer.java void start(String iface, DhcpParams params) { mHandler.post(() -> { mPacketListener = new PacketListener(iface); // 监听usb0接口 mPacketListener.start(); // 启动DHCP报文处理线程 // 配置IP池范围 mLeases.addRange( Inet4Address.parseNumericAddress("192.168.42.2"), Inet4Address.parseNumericAddress("192.168.42.254") ); }); } ``` DHCP服务监听`usb0`接口,IP分配范围为`$192.168.42.2 - 192.168.42.254$`[^1][^2]。 --- #### 4. **DHCP请求处理** 当客户端连接时,`DhcpPacketHandler`处理DHCP请求: ```java // DhcpPacketHandler.java void handlePacket(DhcpPacket packet) { switch (packet.getType()) { case DHCPDISCOVER: Inet4Address clientIp = allocateFreeAddress(); // 分配空闲IP sendOfferPacket(clientMac, clientIp); // 发送DHCPOFFER break; case DHCPREQUEST: commitLease(clientMac, requestedIp); // 确认IP租约 sendAckPacket(clientMac, requestedIp); // 发送DHCPACK break; } } ``` 采用标准DHCP四步握手:DISCOVER→OFFER→REQUEST→ACK[^2]。 --- #### 5. **防火墙与NAT配置** 通过`iptables`启用网络地址转换: ```bash # 配置NAT转发规则 iptables -t nat -A POSTROUTING -o rmnet_data0 -j MASQUERADE # 开启IP转发 sysctl -w net.ipv4.ip_forward=1 ``` 使客户端可通过手机移动网络访问外部资源[^1]。 --- #### 6. **接口状态同步** 通过广播通知系统服务: ```java // UsbManager.java sendStickyBroadcast(new Intent(ACTION_USB_STATE) .putExtra(USB_CONFIGURED, true) .putExtra(USB_FUNCTION_RNDIS, true)); ``` 触发系统更新网络状态(如参考引用中提到的广播`rgb.intent.action.SET_ETH_IFACE`)[^3]。 --- ### 关键设计特点 1. **固定子网段**:始终使用`$192.168.42.0/24$`子网避免冲突 2. **DHCP租约时间**:默认`$3600$`秒(1小时) 3. **无状态分配**:不保存永久租约,断开即释放IP 4. **强隔离**:通过`SELinux`限制`netd`权限
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值