达到 android6.0 wifi连接外网,ethernet连接内网局域网
1、修改 framework 层代码,使得 wif 和 ethernet 同时存在
由于我们的目标时wifi连接外网,ethernet访问特定局域网,所有设置 wifi 优先,ethernet 进行单独配置。

修改wifi优先,在 NetworkAgentInfo.java的方法getCurrentScore() 中加入:

if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { 
 return MAXIMUM_NETWORK_SCORE; 
 }


这样 wifi 的分值就最高了。

修改 wifi 连接上的情况下,插入有线会主动连接。由于上面将 wifi 的优先级调到最高了,所有插入有线时,
判断当前网络连接优先级高于有线,所以不会主动连接有线。在 EthernetNetworkFactory.java的方法 updateInterfaceState
中加入

mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); 
 if (up) { 
 mFactory.startNetwork(); 
 }


这样只有已插入网线就会主动去连接

还是由于wifi优先,如果先连接有线再打开wifi,去连接wifi时会关闭有线。这个时候需要修改 ConnectivityService.java中的方法

private void teardownUnneededNetwork(NetworkAgentInfo nai) { 
 /*for (int i = 0; i < nai.networkRequests.size(); i++) { 
 NetworkRequest nr = nai.networkRequests.valueAt(i); 
 // Ignore listening requests. 
 if (!isRequest(nr)) continue; 
 loge(“Dead network still had at least ” + nr); 
 break; 
 } 
 nai.asyncChannel.disconnect();*/ 
 }


这样就不会去关闭其他连接了。

经过以上的修改,达到了 wifi 和 ethernet 同时存在,而且 wifi 优先正常访问外网的目的。

2、wifi 和 ethernet 同时存在,考虑配置静态路由使得 ethernet 访问指定网络。
修改 dhcpcd.c 中的 main 方法,可以使 dhcp 服务器下发的静态路由添加到路由表中。

case ‘a’: 
 syslog(LOG_INFO, “avoid_routes one %d”, avoid_routes); 
 //avoid_routes = 1; 
 syslog(LOG_INFO, “avoid_routes two %d”, avoid_routes); 
 break;

此时用 route 命令查看,可以看到路由表中多了一条 192.168.10.0 192.168.2.1 255.255.255.0 UG 202 0 0 eth0
:/ # route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.2.0 * 255.255.255.0 U 202 0 0 eth0
192.168.3.0 * 255.255.255.0 U 0 0 0 wlan0
192.168.10.0 192.168.2.1 255.255.255.0 UG 202 0 0 eth0

但是实际上此路由表不会起到任何作用。因为在 android6.0 开始使用了策略路由,如下是 wifi 和 ethernet 同时连接情况下的 策略路由信息

:/ # ip rule list 
 0: from all lookup local 
 10000: from all fwmark 0xc0000/0xd0000 lookup legacy_system 
 10500: from all oif wlan0 uidrange 0-0 lookup wlan0 
 10500: from all oif eth0 uidrange 0-0 lookup eth0 
 13000: from all fwmark 0x10063/0x1ffff lookup local_network 
 13000: from all fwmark 0x10065/0x1ffff lookup wlan0 
 13000: from all fwmark 0x10066/0x1ffff lookup eth0 
 14000: from all oif wlan0 lookup wlan0 
 14000: from all oif eth0 lookup eth0 
 15000: from all fwmark 0x0/0x10000 lookup legacy_system 
 16000: from all fwmark 0x0/0x10000 lookup legacy_network 
 17000: from all fwmark 0x0/0x10000 lookup local_network 
 19000: from all fwmark 0x65/0x1ffff lookup wlan0 
 19000: from all fwmark 0x66/0x1ffff lookup eth0 
 22000: from all fwmark 0x0/0xffff lookup wlan0 
 23000: from all fwmark 0x0/0xffff uidrange 0-0 lookup main 
 32000: from all unreachable

同时可以看到 route 命令查看的实际上是 main 路由表的路由信息
:/ # ip route list table main
192.168.2.0/24 dev eth0 proto kernel scope link src 192.168.2.247 metric 202
192.168.3.0/24 dev wlan0 proto kernel scope link src 192.168.3.146
192.168.10.0/24 via 192.168.2.1 dev eth0 metric 202

所以从上面的分析可以得出结论,单纯依靠 dhcp 下发静态路由,并不能到达效果。

3、android6.0 策略路由
:/ # ip rule list
0: from all lookup local
10000: from all fwmark 0xc0000/0xd0000 lookup legacy_system
10500: from all oif wlan0 uidrange 0-0 lookup wlan0
10500: from all oif eth0 uidrange 0-0 lookup eth0
13000: from all fwmark 0x10063/0x1ffff lookup local_network
13000: from all fwmark 0x10065/0x1ffff lookup wlan0
13000: from all fwmark 0x10066/0x1ffff lookup eth0
14000: from all oif wlan0 lookup wlan0
14000: from all oif eth0 lookup eth0
15000: from all fwmark 0x0/0x10000 lookup legacy_system
16000: from all fwmark 0x0/0x10000 lookup legacy_network
17000: from all fwmark 0x0/0x10000 lookup local_network
19000: from all fwmark 0x65/0x1ffff lookup wlan0
19000: from all fwmark 0x66/0x1ffff lookup eth0
22000: from all fwmark 0x0/0xffff lookup wlan0
23000: from all fwmark 0x0/0xffff uidrange 0-0 lookup main
32000: from all unreachable

从这个路由规则中可以看到, 路由表 local优先,然后是netid 对应 0x10065 的走 wlan0 路由表,对应 0x10066 走 eth0 路由表。
而通常情况下访问网络时没有设置 netid,默认就使用 22000: from all fwmark 0x0/0xffff lookup wlan0 这个,即 wlan0 路由表。
netid 指定在 android6.0中应用可以通过 bindProcessToNetwork() 来指定使用wlan或者ethernet进行网络访问。

看下各个路由表中的信息:
:/ # ip route list table wlan0
default via 192.168.3.1 dev wlan0 proto static
192.168.3.0/24 dev wlan0 proto static scope link

:/ # ip route list table eth0
default via 192.168.2.1 dev eth0 proto static
192.168.2.0/24 dev eth0 proto static scope link

以上静态路由无法达到目的,策略路由不知道如何通过dhcp配置,而且就算配置也只能对应在 eth0 表中,但起作用的是 wlan0 这个路由表。
所以这条路放弃,换个思路。

4、自由选择要使用的网络
13000: from all fwmark 0x10066/0x1ffff lookup eth0 看这条路由信息,可以想到如果对应 app 在访问指定网络时设置 netid 为 0x10066,是否就可以用 eth0 访问指定网络。
接着 android6.0 的网络相关的新功能, bindProcessToNetwork 接口。
详细使用可以参照原生代码中 CaptivePortalLoginActivity 类。

这个调用的过程可以参考