架构
ConnectivityService
ConnectivityService(简称CS)是Android系统中的网络连接大管家,所有类型(如WiFi、Telephony、Ethernet等)的网络都需要注册关联到CS并提供链路请求接口。CS主要提供了以下几个方面的功能:
- 网络有效性检测(NetworkMonitor)
- 网络评分与选择(NetworkFactory、NetworkAgent、NetworkAgentInfo)
- 网口、路由、DNS等参数配置(netd)
- 向系统及三方提供网络申请接口(ConnectivityManager)
dumpsys connectivity
NetworkFactories for: WIFI_UT Ethernet TelephonyNetworkFactory[0] PhoneSwitcherNetworkRequstListener WIFI
Active default network: 101
Current Networks:
NetworkAgentInfo{ ni{[type: MOBILE[LTE], state: CONNECTED/CONNECTED, reason: connected, extra: cmnet, failover: false, available: true, roaming: false, metered: true]} network{101} nethandle{433808132830} lp nc{[ Transports: CELLULAR Capabilities: SUPL&INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&VALIDATED&FOREGROUND LinkUpBandwidth>=51200Kbps LinkDnBandwidth>=102400Kbps Specifier: <1>]} Score{50} everValidated{true} lastValidated{true} created{true} lingering{false} explicitlySelected{false} acceptUnvalidated{false} everCaptivePortalDetected{false} lastCaptivePortalDetected{false} }
Requests: REQUEST:1 LISTEN:4 BACKGROUND_REQUEST:0 total:5
NetworkRequest [ REQUEST id=1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
NetworkRequest [ LISTEN id=3, [] ]
NetworkRequest [ LISTEN id=4, [ Transports: CELLULAR|WIFI Capabilities: NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
NetworkRequest [ LISTEN id=6, [ Transports: CELLULAR Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
NetworkRequest [ LISTEN id=7, [] ]
Lingered:
Metered Interfaces:
rmnet_data0
Restrict background: false
Status for known UIDs:
UID=10008 rules=1 (ALLOW_METERED)
UID=10027 rules=1 (ALLOW_METERED)
Network Requests:
uid/pid:1000/1911 NetworkRequest [ LISTEN id=5, [ Transports: WIFI Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
uid/pid:10033/1679 NetworkRequest [ LISTEN id=7, [] ]
uid/pid:1000/1378 NetworkRequest [ LISTEN id=4, [ Transports: CELLULAR|WIFI Capabilities: NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
uid/pid:1000/1378 NetworkRequest [ LISTEN id=3, [] ]
uid/pid:1000/1378 NetworkRequest [ REQUEST id=1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
uid/pid:1000/1911 NetworkRequest [ LISTEN id=6, [ Transports: CELLULAR Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
mLegacyTypeTracker:
Supported types: 0 1 2 3 4 5 7 10 11 12 15 17
Current state:
0 NetworkAgentInfo [MOBILE (LTE) - 101] CONNECTED/CONNECTED
mNetTransitionWakeLock: currently not held, last requested for NetworkAgentInfo [MOBILE (LTE) - 100]
Tethering:
mUpstreamIfaceTypes: MOBILE WIFI MOBILE_HIPRI BLUETOOTH
Tether state:
Packet keepalives:
Bad Wi-Fi avoidance: unrestricted
mValidationLogs (most recent first):
101 - cmnet
08-28 13:48:51.362 - PROBE_DNS connect.rom.miui.com 101ms OK 111.13.213.168,39.156.81.215
08-28 13:48:51.488 - PROBE_HTTP http://connect.rom.miui.com/generate_204 time=122ms ret=204 request={User-Agent=[Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36]} headers={null=[HTTP/1.1 204 No Content], Connection=[close], Date=[Wed, 28 Aug 2019 05:48:52 GMT], X-Android-Received-Millis=[1566971331486], X-Android-Response-Source=[NETWORK 204], X-Android-Selected-Protocol=[http/1.1], X-Android-Sent-Millis=[1566971331426]}
100 - cmnet
08-28 13:48:48.042 - PROBE_DNS connect.rom.miui.com 27ms FAIL
08-28 13:48:48.075 - PROBE_HTTP http://connect.rom.miui.com/generate_204 Probably not a portal: exception java.net.UnknownHostException: Unable to resolve host "connect.rom.miui.com": No address associated with hostname
08-28 13:48:48.081 - trying to use fallback URL
08-28 13:48:48.090 - PROBE_FALLBACK http://developers.google.cn/generate_204 Probably not a portal: exception java.net.UnknownHostException: Unable to resolve host "developers.google.cn": No address associated with hostname
08-28 13:48:48.090 - trying to use fallback URL
08-28 13:48:48.096 - PROBE_FALLBACK http://www.google.com/gen_204 Probably not a portal: exception java.net.UnknownHostException: Unable to resolve host "www.google.com": No address associated with hostname
mNetworkRequestInfoLogs (most recent first):
08-28 13:48:03.261 - REGISTER uid/pid:10033/1679 NetworkRequest [ LISTEN id=7, [] ]
08-28 13:48:03.095 - REGISTER uid/pid:1000/1911 NetworkRequest [ LISTEN id=6, [ Transports: CELLULAR Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
08-28 13:48:03.095 - REGISTER uid/pid:1000/1911 NetworkRequest [ LISTEN id=5, [ Transports: WIFI Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
08-28 13:48:02.400 - REGISTER uid/pid:1000/1378 NetworkRequest [ LISTEN id=4, [ Transports: CELLULAR|WIFI Capabilities: NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
08-28 13:47:59.797 - REGISTER uid/pid:1000/1378 NetworkRequest [ LISTEN id=3, [] ]
08-28 13:47:59.157 - REGISTER uid/pid:1000/1378 NetworkRequest [ REQUEST id=1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
mNetworkInfoBlockingLogs (most recent first):
NetworkFactory
系统中的网络工厂,也是CS向链路网络请求的统一接口。Android系统启动之初,数据和WiFi就通过WifiNetworkFactory和TelephonyNetworkFactory将自己注册到CS中,方便CS迅速响应网络请求。
NetworkFactory继承自Handler,并通过AsyncChannel(对Messenger的一种包装,维护了连接的状态,本质上使用Messenger)建立了CS和WifiStateMachine之间的单向通信:
/**
* A NetworkFactory is an entity that creates NetworkAgent objects.
* The bearers register with ConnectivityService using {@link #register} and
* their factory will start receiving scored NetworkRequests. NetworkRequests
* can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by
* overridden function. All of these can be dynamic - changing NetworkCapabilities
* or score forces re-evaluation of all current requests.
*
* If any requests pass the filter some overrideable functions will be called.
* If the bearer only cares about very simple start/stopNetwork callbacks, those
* functions can be overridden. If the bearer needs more interaction, it can
* override addNetworkRequest and removeNetworkRequest which will give it each
* request that passes their current filters.
* @hide
**/
public class NetworkFactory extends Handler {
public void register() {
if (DBG) log("Registering NetworkFactory");
if (mMessenger == null) {
// 创建以自己为Handler的Messenger并传递给CS
// 之后CS就能够使用Messenger通过Binder的形式与WifiStateMachine线程通信
mMessenger = new Messenger(this);
ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);
}
}
}
CS通过NetworkFactory和WifiStateMachine单向通信:
NetworkAgent
链路网络的代理,是CS和链路网络管理者(如WifiStateMachine)之间的信使,在L2连接成功后创建。通过NetworkAgent,WifiStateMachine可以向CS:
- 更新网络状态 NetworkInfo(断开、连接中、已连接等)
- 更新链路配置 LinkProperties(本机网口、IP、DNS、路由信息等)
- 更新网络能力 NetworkCapabilities(信号强度、是否收费等)
CS可以向WifiStateMachine:
- 更新网络有效性(即NetworkMonitor的网络检测结果)
- 禁止自动连接
- 由于网络不可上网等原因主动断开网络
因此,NetworkAgent提供了CS和WifiStateMachine之间双向通信的能力。原理类似NetworkFactory,也是使用了AsyncChannel和Messenger。
CS和WifiStateMachine通过NetworkAgent进行双向通信:
NetworkMonitor
在链路网络注册到CS,并且所有网络配置信息都已经向netd完成了配置,此时就会开始进行网络诊断,具体诊断的任务交给NetworkMonitor。
NetworkMonitor也是一个状态机,包含以下几种基本状态:
State | Description |
---|---|
DefaultState | 初始状态。接收CS网络诊断命令消息后触发诊断;接收用户登录网络消息 |
MaybeNotifyState | 通知用户登录。接收诊断后发送的”CMD_LAUNCH_CAPTIVE_PORTAL_APP”消息,startActivity显示登录页面 |
EvaluatingState | 诊断状态。进入时发送”CMD_REEVALUATE”消息,接收 “CMD_REEVALUATE” 消息并执行网络诊断过程 |
CaptivePortalState | 登录状态。进入时发送”CMD_LAUNCH_CAPTIVE_PORTAL_APP”消息显示登录页面,发送10分钟延迟的”CMD_CAPTIVE_PORTAL_RECHECK”消息进行再次诊断 |
ValidatedState | 已验证状态。进入时发送”EVENT_NETWORK_TESTED”通知CS网络诊断完成 |
EvaluatingPrivateDnsState | 私密DNS验证状态。Android Pie验证私密DNS推出。 |
NetworkPolicyManagerService
NetworkPolicyManagerService(简称NPMS)是Android系统的网络策略管理者。NPMS会监听网络属性变化(是否收费,metered)、应用前后台、系统电量状态(省电模式)、设备休眠状态(Doze),在这些状态发生改变时,为不同名单内的网络消费者配置不同的网络策略。
网络策略的基本目的:
- 在收费网络的情况下省流量
- 最大可能性的省电
- 防止危险流量进入
网络策略中几个重要的名单:
NameList | Description |
---|---|
mUidFirewallStandbyRules | 黑名单,针对前后台应用。此名单中的APP默认REJECT,可配置ALLOW。 |
mUidFirewallDozableRules | 白名单,针对Doze。此名单中的APP在Doze情况下默认ALLOW。 |
mUidFirewallPowerSaveRules | 白名单,针对省电模式(由Battery服务提供)。此名单中的APP在省电模式下默认ALLOW,但在Doze情况下仍然REJECT。 |
NPMS对网络策略进行统一管理和记录,并配合netd和iptables/ip6tables工具,达到网络限制的目的。
dumpsys netpolicy
System ready: true
Restrict background: false
Restrict power: false
Device idle: false
Network policies:
NetworkPolicy[NetworkTemplate: matchRule=MOBILE_ALL, subscriberId=460110..., matchSubscriberIds=[460110...]]: cycleDay=1, cycleTimezone=Asia/Shanghai, warningBytes=2147483648, limitBytes=-1, lastWarningSnooze=-1, lastLimitSnooze=-1, metered=true, inferred=false
NetworkPolicy[NetworkTemplate: matchRule=MOBILE_ALL, matchSubscriberIds=[null]]: cycleDay=27, cycleTimezone=Asia/Shanghai, warningBytes=2147483648, limitBytes=-1, lastWarningSnooze=-1, lastLimitSnooze=-1, metered=true, inferred=true
NetworkPolicy[NetworkTemplate: matchRule=MOBILE_ALL, subscriberId=460040..., matchSubscriberIds=[460040...]]: cycleDay=27, cycleTimezone=Asia/Shanghai, warningBytes=2147483648, limitBytes=-1, lastWarningSnooze=-1, lastLimitSnooze=-1, metered=true, inferred=true
Metered ifaces: {rmnet_data0}
Policy for UIDs:
Power save whitelist (except idle) app ids:
UID=10008: true
UID=10027: true
Power save whitelist app ids:
UID=10008: true
UID=10027: true
Restrict background whitelist uids:
UID=10008
UID=10027
Default restrict background whitelist uids:
UID=10008
UID=10027
Status for all known UIDs:
UID=1001 state=0 (fg) rules=0 (NONE)
....................................
Status for just UIDs with rules:
UID=10008 rules=1 (ALLOW_METERED)
UID=10027 rules=1 (ALLOW_METERED)
NetworkManagementService
Android SystemServer不具备直接配置和操作网络的能力,所有的网络参数(网口、IP、DNS、Router等)配置,网络策略执行都需要通过netd这个native进程来实际执行或者传递给Kernel来执行。
而NetworkManagementService(简称NMS)就是SystemServer中其他服务连接netd的桥梁。
NMS和netd之间通信的方式有两种:Binder 和 Socket。为什么不全使用Binder?原因在于Android老版本上像 vold、netd 这种native进程和SystemServer通信的方式都是使用的Socket,目前高版本上也在慢慢的Binder化,提升调用速度。
SystemServer和netd之间的数据流向图:
dumpsys network_management
NetworkManagementService NativeDaemonConnector Log:
08-28 13:48:47.875 - RCV <- {200 30 MTU changed}
08-28 13:48:47.876 - SND -> {31 network route add 100 rmnet_data0 0.0.0.0/0 10.156.246.136}
08-28 13:48:47.880 - RCV <- {200 31 success}
08-28 13:48:47.893 - SND -> {32 bandwidth gettetherstats}
08-28 13:48:47.896 - RCV <- {200 32 Tethering stats list completed}
08-28 13:48:47.912 - RCV <- {600 Iface linkstate rmnet_data0 down}
08-28 13:48:47.922 - RCV <- {616 Route removed fe80::/64 dev rmnet_data0}
08-28 13:48:47.922 - RCV <- {614 Address removed fe80::c980:eef2:32dd:10c1/64 rmnet_data0 128 253}
08-28 13:48:47.973 - SND -> {33 bandwidth gettetherstats}
08-28 13:48:47.977 - RCV <- {200 33 Tethering stats list completed}
08-28 13:48:48.006 - SND -> {34 idletimer add rmnet_data0 10 0}
08-28 13:48:48.035 - RCV <- {614 Address removed 10.156.246.135/28 rmnet_data0 128 0}
08-28 13:48:48.294 - RCV <- {200 34 Add success}
08-28 13:48:48.295 - SND -> {35 network default set 100}
08-28 13:48:48.297 - RCV <- {200 35 success}
08-28 13:48:48.348 - SND -> {36 bandwidth gettetherstats}
08-28 13:48:48.349 - RCV <- {200 36 Tethering stats list completed}
08-28 13:48:48.402 - SND -> {37 idletimer remove rmnet_data0 10 0}
08-28 13:48:48.723 - RCV <- {200 37 Remove success}
08-28 13:48:48.728 - SND -> {38 network destroy 100}
08-28 13:48:48.795 - SND -> {39 bandwidth setglobalalert 2097152}
08-28 13:48:49.546 - RCV <- {200 38 success}
.................................................................
Pending requests:
Bandwidth control enabled: true
mMobileActivityFromRadio=false mLastPowerStateFromRadio=1
mNetworkActive=false
Active quota ifaces: {rmnet_data0=9223372036854775807}
Active alert ifaces: {}
Data saver mode: false
UID bandwith control blacklist rule: []
UID bandwith control whitelist rule: [10008,10027]
UID firewall rule: []
UID firewall standby chain enabled: false
UID firewall standby rule: []
UID firewall dozable chain enabled: false
UID firewall dozable rule: []
UID firewall powersave chain enabled: false
UID firewall powersave rule: []
Idle timers:
rmnet_data0:
timeout=10 type=0 networkCount=1
Firewall enabled: false
Netd service status: alive
netd
为了保障各个功能的正常运行,Android系统中有非常多的守护进程(Daemon)。为了保证系统起来后各项功能都已经ready,这些daemon进程跟随系统的启动而启动,而且一般比system_server进程先启动。如存储相关的vold、电话相关的rild、以及网络相关netd等, netd进程由init进程启动
$ ps |grep -E "netd|vold|rild|system_server"
root 364 1 44036 3272 hrtimer_na 00000000 S /system/bin/vold
root 761 1 24736 2776 binder_thr 00000000 S /system/bin/netd
radio 762 1 84876 14388 hrtimer_na 00000000 S /system/bin/rild
system 1378 692 1808024 114108 SyS_epoll_ 00000000 S system_server
netd作为Android系统的网络守护者,主要有以下方面的职能:
- 处理接收来自Kernel的UEvent消息(包含网络接口、带宽、路由等信息),并传递给Framework
- 提供防火墙设置、网络地址转换(NAT)、带宽控制、网络设备绑定(Tether)等接口
- 管理和缓存DNS信息,为系统和应用提供域名解析服务
wpa_supplicant
与netd一样,也是Android系统的一个daemon进程,与netd不同的是,它只有在WiFi开启的情况下才会启动,在WiFi关闭的时候会随之关闭。wpa_supplicant向Framework提供了WiFi配置、连接、断开等接口。
wpa_supplicant比Android的历史要早,在很多其他平台上也被广泛利用,他增加了对更多RFC协议的支持,这也是Google最初选择它的原因。但从Android近几个版本来看,Google还是希望弱化wpa_supplicant,并将其功能迁移至Framework或者其他daemon进程中。Android 8.0发生的几个改变:
与system_server的通信从原来的Socket通信改成了HIDL,提高了速度、便于system分区自升级 扫描的功能迁移到了system/wificond中,弱化wpa_supplicant
wpa_supplicant和Framework通信: