Android 系统Framework进行一定适配后,可以实现wifi和有线网络端口都打开的,
进而在App端即可实现通过代码控制选择使用wifi或者有线网络进行网络请求。
本文只介绍wifi和有线网络端口同时打开的实现,app代码请求特定网络另外文章介绍。
Android 默认是只保留打开一个网络的,其他网络是关闭的;
手机一般是wifi或者Sim卡;
一些的定制设备,比如商显大屏或者Android盒子,一般是wifi或者有线网络(以太网)。
Android 系统6以后网络切换是以Score分值进行判断,分值越高越优先,
比如wifi的分值为60,Sim卡的分值为50,所以wifi连接成功后,优先使用的是wifi网络。
有线网的分值为70,比wifi优先。
这个Score根据不同系统版本和设备情况,Score分值会有不同,但是都是根据分值确定确定优先级的。
优先级的判断主要在 NetworkFactory.java和它的子类WifiNetworkFactory.java、EthernetNetworkFactory.java
网络的切换逻辑判断主要在ConnectivityService.java类
不同的系统版本位置不一样,需要在自己代码环境中查找
find . -name “NetworkFactory.java”
看了很多网上的方法,都不能生效,估计是Android11 代码结构有修改。
对比了下Android9和Android11的 ConnectivityService.java ,发现变化很大,逻辑变得复制了很多。
找了很多网上的方法说是把 teardownUnneededNetwork方法的nai.asyncChannel.disconnect()注释掉就可以了;
frameworks\base\services\core\java\com\android\server\ConnectivityService.java
private void teardownUnneededNetwork(NetworkAgentInfo nai) {
if (nai.numRequestNetworkRequests() != 0) {
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
// Ignore listening requests.
if (nr.isListen()) continue;
loge("Dead network still had at least " + nr);
break;
}
}
//nai.asyncChannel.disconnect();
}
但是我试了一下,在Android11 不行哎,
搜索发现 ConnectivityService.java里面还有两个 nai.asyncChannel.disconnect(),把这两个都注释掉就可以了。
研究过网络请求和释放,会知道网络的最终执行都是在NetworkFactory和相关子类;
所以在NetworkFactory.java把网络释放注释掉是最保险的。
因为在ConnectivityService到NetworkFactory直接还有很多相关的代理对象和过程。
frameworks\libs\net\common\src_servicescommon\android\net\NetworkFactory.java
private void evalRequest(NetworkRequestInfo n) {
if (VDBG) {
log("evalRequest");
log(" n.requests = " + n.requested);
log(" n.score = " + n.score);
log(" mScore = " + mScore);
log(" request.providerId = " + n.providerId);
log(" mProvider.id = " + mProvider.getProviderId());
}
if (shouldNeedNetworkFor(n)) { //1、要确保执行到needNetworkFor方法一次,才能正常请求网络,shouldNeedNetworkFor方法根据情况进行修改,或者直接返回true;
if (VDBG) log(" needNetworkFor");
needNetworkFor(n.request, n.score);
n.requested = true;
} else if (shouldReleaseNetworkFor(n)) {
if (VDBG) log(" releaseNetworkFor");
//releaseNetworkFor(n.request); //2、把执行网络释放的操作注释即可。
//n.requested = false;
} else {
if (VDBG) log(" done");
}
}
当然这两个部分的代码都修改是没问题的。
最好也是这两部分都进行修改,避免后期连接不上的问题。
Android13 系统上虽然目录不同了,但是就要两者都改,不然有bug!
主要命令:
adb shell ifconfig //查看配置信息
adb shell dumpsys connectivity //查看连接情况,信息更详细,有Score等信息
C:\Users\liwenzhi>adb shell ifconfig
wlan0 Link encap:Ethernet HWaddr 20:32:33:91:23:9e Driver usb
inet addr:192.168.43.53 Bcast:192.168.43.255 Mask:255.255.255.0
inet6 addr: 2409:8955:3848:1a7e:5123:75a1:44e9:d36b/64 Scope: Global
RX bytes:89876 TX bytes:1597990
...
eth0 Link encap:Ethernet HWaddr 02:ad:36:01:8a:3d Driver meson8b-dwmac
inet addr:192.5.1.17 Bcast:192.5.1.255 Mask:255.255.255.0
collisions:0 txqueuelen:1000
RX bytes:1549861 TX bytes:1983944
Interrupt:48
C:\Users\liwenzhi>
这里wifi(wlan0)和有线网络(eth0)都存在ip,表示可以进行连接
Active default network: 101
Current Networks:
//其中一个网络,有线网
NetworkAgentInfo{ ni{[type: Ethernet[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: 02:ad:36:01:8a:3d, failover: false,
available: true, roaming: false]} network{100} nethandle{432902426637} lp{{InterfaceName: eth0 LinkAddresses: [ fe80::5f92:6ddf:1843:9ffa/64,192.5.1.6/24 ]
Requests: REQUEST:0 LISTEN:3 BACKGROUND_REQUEST:0 total:3
NetworkRequest [ LISTEN id=4, [ Capabilities: FOREGROUND AdministratorUids: [] RequestorUid: 1000 RequestorPackageName: android] ]
NetworkRequest [ LISTEN id=5, [ Capabilities: NOT_RESTRICTED&TRUSTED&NOT_VPN&FOREGROUND Uid: 1000 AdministratorUids: [] RequestorUid: 1000 RequestorPackageName: android] ]
NetworkRequest [ LISTEN id=7, [ Capabilities: NOT_RESTRICTED&TRUSTED&NOT_VPN Uid: 1000 AdministratorUids: [] RequestorUid: 1000 RequestorPackageName: android] ]
Lingered: //之前的请求信息(不是当前的)
NetworkRequest [ REQUEST id=1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN AdministratorUids: [] RequestorUid: 1000 RequestorPackageName: android] ], expires 24995ms
NetworkRequest [ TRACK_DEFAULT id=8, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED Uid: 1000 AdministratorUids: [] RequestorUid: 1000 RequestorPackageName: android] ], expires 24995ms
//另一个网络,wifi
NetworkAgentInfo{ ni{[type: WIFI[], state: CONNECTED/CONNECTED, reason: (unspecified), extra: , failover: false,
available: true, roaming: false]} network{101} nethandle{437197393933} lp{{InterfaceName: wlan0 LinkAddresses: [ fe80::bbbb:2be7:6b3f:67da/64,192.5.1.27/24 ] DnsAddresses: [ /192.5.1.1 ]
Requests: REQUEST:2 LISTEN:8 BACKGROUND_REQUEST:0 total:10
NetworkRequest [ REQUEST id=1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN AdministratorUids: [] RequestorUid: 1000 RequestorPackageName: android] ]
NetworkRequest [ LISTEN id=4, [ Capabilities: FOREGROUND AdministratorUids: [] RequestorUid: 1000 RequestorPackageName: android] ]
NetworkRequest [ LISTEN id=5, [ Capabilities: NOT_RESTRICTED&TRUSTED&NOT_VPN&FOREGROUND Uid: 1000 AdministratorUids: [] RequestorUid: 1000 RequestorPackageName: android] ]
NetworkAgentInfo 表示一个网络
像上面这种情况,默认使用的是wifi网络;
如果wifi和有线网络不在同一个网段的情况,
可以在adb shell里面直接ping通连接通同一个wifi网段的其他ip,但是ping不通同一个有线网络网段的ip;
但是可以通过指定网络端口进行连接 ping -I NetName ip
主要命令:
adb shell
//使用wifi 网络访问某个网址
ping -I wlan0 XXX.XXX.XXX.XXX
//使用有线网网络访问某个网址
ping -I eht0 XXX.XX.XXX.XXX
有线网和wifi可以一个连接局域网,一个连接手机热点网络
或者一个连接内网,一个连接VPN网络。
https://ip.bczs.net 网址可以查询国外网址的ip
比如浏览器输入:
https://ip.bczs.net/www.youtube.com
网页就会显示:
您查询的 域名:www.youtube.com --> 142.250.204.110
所属国家/地区:美国(US)
路由信息:142.250.204.0/24
区域号码:AS15169
区域名称:GOOGLE
描述信息:
比如这里测试,有线网eth0 接入的是公司内网,wifi连接的是VPN路由器网络:
130|console:/ #
130|console:/ # //有线网 测试连接 YouTube,无法连通
130|console:/ # ping -I eth0 172.217.24.78
PING 172.217.24.78 (172.217.24.78) from 192.168.31.71 eth0: 56(84) bytes of data.
^C
--- 172.217.24.78 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4054ms
1|console:/ #
1|console:/ # // wifi 测试连接 YouTube,正常连通
1|console:/ # ping -I wlan0 172.217.24.78
PING 172.217.24.78 (172.217.24.78) from 192.5.1.8 wlan0: 56(84) bytes of data.
64 bytes from 172.217.24.78: icmp_seq=1 ttl=53 time=134 ms
64 bytes from 172.217.24.78: icmp_seq=2 ttl=53 time=27.5 ms
64 bytes from 172.217.24.78: icmp_seq=3 ttl=53 time=46.5 ms
64 bytes from 172.217.24.78: icmp_seq=4 ttl=53 time=41.0 ms
64 bytes from 172.217.24.78: icmp_seq=5 ttl=53 time=29.3 ms
^C
--- 172.217.24.78 ping statistics ---
130|console:/ # ^C
130|console:/ # ping -I wlan0 www.baidu.com // wifi 测试连接 baidu,正常连通
PING www.a.shifen.com (157.148.69.74) from 192.5.1.8 wlan0: 56(84) bytes of data.
64 bytes from 157.148.69.74: icmp_seq=1 ttl=41 time=132 ms
64 bytes from 157.148.69.74: icmp_seq=2 ttl=41 time=103 ms
64 bytes from 157.148.69.74: icmp_seq=3 ttl=41 time=113 ms
^C
--- www.a.shifen.com ping statistics ---
7 packets transmitted, 7 received, 0% packet loss, time 6004ms
rtt min/avg/max/mdev = 84.540/107.435/132.974/13.661 ms
console:/ #
console:/ #
console:/ # ping -I eth0 www.baidu.com //有线网 测试连接baidu,正常连通
PING www.a.shifen.com (157.148.69.74) from 192.168.31.71 eth0: 56(84) bytes of data.
64 bytes from 157.148.69.74: icmp_seq=1 ttl=48 time=14.2 ms
64 bytes from 157.148.69.74: icmp_seq=2 ttl=48 time=13.5 ms
64 bytes from 157.148.69.74: icmp_seq=3 ttl=48 time=13.6 ms
64 bytes from 157.148.69.74: icmp_seq=4 ttl=48 time=13.6 ms
^C
--- www.a.shifen.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 13.511/13.768/14.231/0.309 ms
console:/ #
可以看到连接VPN网络的wifi 是可以正常访问外网,公司内网无法访问外网!百度网页是内网和外网都可以正常联通的。
证明有线网和wifi 是有区分的,并且都是可以正常访问外部和被外部访问的。