系列目录 :第一篇:全景图与调用链路概览 | 第二篇:内核层---netfilter/iptables与路由策略 | 第三篇:Native层(上)---netd守护进程与CommandListener | 第四篇:Native层(下)---netd Controller详解 | 第五篇:Framework层(上)---ConnectivityService核心机制 | 第六篇:Framework层(下)---NMS/NPMS/NSS三大服务 | 第七篇:连接建立---WiFi/移动数据/以太网完整流程 | 第八篇:应用API层---ConnectivityManager使用与实战调试
一、ConnectivityService 概述
ConnectivityService 是 Framework 层最核心的网络服务,负责管理系统中所有网络连接的状态。如果把 Android 网络比作一座城市,ConnectivityService 就是交通调度中心------它决定哪个网络是"默认网络"、何时切换网络、如何处理应用的网络请求。
源码路径 : frameworks/base/services/core/java/com/android/server/ConnectivityService.java
核心职责:
| 职责 | 说明 |
|---|---|
| 管理 NetworkAgent | 维护所有活跃网络连接(WiFi、移动数据、以太网等)的代理 |
| 评分与选择 | 比较各网络的评分,决定默认网络 |
| 处理 NetworkRequest | 应用请求特定类型网络时的分配 |
| 网络切换 | 在可用网络之间自动切换 |
| 广播通知 | 发送 CONNECTIVITY_ACTION 广播 |
| Legacy 类型支持 | 兼容旧的 TYPE_WIFI / TYPE_MOBILE API |
二、启动流程
ConnectivityService 在 SystemServer 中创建并启动。
源码路径 : frameworks/base/services/java/com/android/server/SystemServer.java
java
// SystemServer.startOtherServices() 中
connectivity = new ConnectivityService(
context, networkManagement, networkStats, networkPolicy);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
networkStats.bindConnectivityManager(connectivity);
networkPolicy.bindConnectivityManager(connectivity);
关键设计 :
ConnectivityService创建后先注册到ServiceManager,再与NetworkStatsService和NetworkPolicyManagerService双向绑定,systemReady()在后续阶段单独调用。
ConnectivityService 构造函数中的初始化:
new ConnectivityService()
├── 创建 InternalHandler(消息处理线程)
├── 创建 NetworkFactoryInfo 列表
├── 创建 NetworkAgentInfo 列表
├── 创建 NetworkRequestInfo 列表
├── 注册 NetworkFactory 的 Trackers
└── 启动 LegacyTypeTracker
关键 :
LegacyTypeTracker在构造函数中初始化,负责维护TYPE_WIFI/TYPE_MOBILE等旧 API 类型到NetworkAgentInfo的映射。
这三个核心数据结构支撑了整个网络管理:
NetworkAgentInfo:每个活跃网络对应一个,包含类型、状态、评分、LinkProperties等NetworkRequestInfo:每个应用网络请求对应一个,包含请求的类型、回调等NetworkFactoryInfo:每个NetworkFactory对应一个,用于生产新网络
三、核心数据结构
3.1 NetworkAgentInfo
源码路径 : frameworks/base/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
java
public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public NetworkInfo networkInfo; // 网络信息(类型、状态等)
public final Network network; // Network 对象
public LinkProperties linkProperties; // IP、网关、DNS 等
public NetworkCapabilities networkCapabilities; // 网络能力
public final NetworkMonitor networkMonitor; // 网络连通性探测器
public final NetworkMisc networkMisc; // 网络杂项配置
public boolean created; // 是否已在 netd 创建
public boolean everConnected; // 是否曾经连接过
public boolean everValidated; // 是否曾经验证通过
public boolean lastValidated; // 最后验证结果
public boolean avoidUnvalidated; // 是否避免未验证网络
// ...
}
关键设计 :
network字段声明为final,保证每个NetworkAgentInfo的Network对象在构造后不再变化;created和everConnected是 sticky bit,一旦设置就不会清除。
3.2 NetworkCapabilities
源码路径 : frameworks/base/core/java/android/net/NetworkCapabilities.java
描述网络能做什么(不能做什么)。
java
public final class NetworkCapabilities {
// Transport 类型
public static final int TRANSPORT_CELLULAR = 0;
public static final int TRANSPORT_WIFI = 1;
public static final int TRANSPORT_ETHERNET = 3;
public static final int TRANSPORT_VPN = 4;
// ...
// 能力定义
public static final int NET_CAPABILITY_INTERNET = 12; // 能上互联网
public static final int NET_CAPABILITY_NOT_METERED = 11; // 不计流量
public static final int NET_CAPABILITY_VALIDATED = 16; // 已验证可上网
// ...
}
关键设计 :
TRANSPORT_*描述网络的传输介质,NET_CAPABILITY_*描述网络的能力,两者独立判断------一个 VPN 可以同时具备TRANSPORT_VPN和NET_CAPABILITY_INTERNET。
3.3 NetworkRequest
源码路径 : frameworks/base/core/java/android/net/NetworkRequest.java
应用通过 NetworkRequest 描述它需要的网络类型:
java
public class NetworkRequest {
public NetworkCapabilities networkCapabilities; // 请求的网络能力
public int legacyType; // 旧 API 中的 TYPE_WIFI 等
public int requestId; // 唯一请求 ID
}
关键 :
legacyType用于兼容旧的TYPE_WIFI/TYPE_MOBILEAPI,新代码应使用networkCapabilities描述需求。
应用构建请求的示例:
java
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
connectivityManager.requestNetwork(request, callback);
关键 :
Builder模式的链式调用让应用可以精确描述网络需求,ConnectivityService根据这些约束匹配最合适的网络。
四、网络评分与选择机制
4.1 整体流程
ConnectivityService 的核心算法是网络评分与匹配。当有新网络出现或有新请求时:
触发条件(新网络建立 / 新请求到达 / 网络断开)
↓
rematchAllNetworksAndRequests()
↓
对每个 NetworkRequest,遍历所有 NetworkAgent
↓
找到评分最高、能力匹配的 NetworkAgent
↓
更新默认网络(如果最高分网络变化)
↓
通知 NetworkCallback(onAvailable / onLost / onCapabilitiesChanged)
关键 :
rematchAllNetworksAndRequests()是重匹配的入口,每次网络拓扑变化时调用,确保默认网络始终是评分最高且满足条件的那一个。
4.2 evalRequest --- 评分核心逻辑
源码路径 : frameworks/base/core/java/android/net/NetworkFactory.java
java
private void evalRequest(NetworkRequestInfo n) {
if (n.requested == false && n.score < mScore &&
n.request.networkCapabilities.satisfiedByNetworkCapabilities(
mCapabilityFilter) && acceptRequest(n.request, n.score)) {
needNetworkFor(n.request, n.score);
n.requested = true;
} else if (n.requested == true &&
(n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities(
mCapabilityFilter) == false || acceptRequest(n.request, n.score) == false)) {
releaseNetworkFor(n.request);
n.requested = false;
}
}
关键设计 :
evalRequest通过比较n.score与当前工厂的mScore决定是否需要此网络------请求的评分低于工厂评分时,工厂接手;请求评分高于工厂评分时,释放网络交给更高评分的工厂。
每个 NetworkFactory 根据自身类型给出基础评分:
| 网络类型 | 基础评分 | 说明 |
|---|---|---|
| 以太网 | 70 | 有线,最稳定 |
| WiFi | 60 | 无线局域网 |
| 移动数据(4G) | 50 | 蜂窝网络 |
| 蓝牙共享 | 69 | 蓝牙网络共享 |
4.3 评分对比实例
假设设备同时连接了 WiFi 和移动数据:
场景:用户开启 WiFi 并连接到路由器
NetworkAgent[WiFi].currentScore = 60
NetworkAgent[MOBILE].currentScore = 50
默认网络请求:
- 遍历所有 NetworkAgent
- WiFi: 60分,具备 INTERNET 能力 ✓
- MOBILE: 50分,具备 INTERNET 能力 ✓
- 最高分:WiFi (60)
结果:WiFi 成为默认网络,所有未绑定网络的应用走 WiFi
关键:评分比较是纯数值比较,不涉及网络类型偏好------只要 WiFi 评分高于移动数据,WiFi 就优先。
WiFi 断开时的切换:
用户关闭 WiFi
↓
NetworkAgent[WiFi] 被移除
↓
rematchAllNetworksAndRequests()
↓
只剩 NetworkAgent[MOBILE] (50分)
↓
移动数据成为默认网络
↓
应用无感知切换(TCP 连接会断开需要重连)
关键 :切换本身对应用无感知(Socket 不会收到断开通知),但已建立的 TCP 连接会因路由变化而中断,应用需要在
onLost回调中重建连接。
4.4 以太网接入时的抢占
当网线插入,以太网接口获得 IP 后,EthernetNetworkFactory 创建一个 NetworkAgent 并注册到 ConnectivityService:
以太网插入
↓
EthernetNetworkFactory 创建 NetworkAgent (score=70)
↓
ConnectivityService.registerNetworkAgent(ethernetAgent)
↓
rematchAllNetworksAndRequests()
↓
WiFi: 60分,MOBILE: 50分,Ethernet: 70分
↓
以太网成为新的默认网络
↓
应用流量切换到以太网出口
关键:以太网因有线连接的特性,评分最高(70),插入网线后会自动抢占 WiFi 的默认网络地位。
五、网络切换流程:WiFi 与 移动数据 全链路
5.1 WiFi 断开到移动数据接管
WifiStateMachine 检测到 WiFi 断开
↓
WifiStateMachine 通知 ConnectivityService: network lost
↓
ConnectivityService.updateNetworkInfo()
↓
NetworkAgentInfo[WiFi].networkInfo.setState(DISCONNECTED)
↓
ConnectivityService.rematchAllNetworksAndRequests()
├── 遍历所有 NetworkAgent
├── WiFi 不可用,跳过
├── MOBILE 可用(score=50)
└── 移动数据成为默认网络
↓
更新默认网络(updateDnses / addDefaultRoute)
↓
发送 CONNECTIVITY_ACTION 广播
↓
通知所有 NetworkCallback: onAvailable(MOBILE)
关键 :切换过程中
updateDnses和addDefaultRoute先执行,确保新网络的 DNS 和路由就绪后才发送广播,避免应用收到广播后发起请求时网络尚未配置完成。
5.2 新 WiFi 连接,从移动数据切换
WifiStateMachine 建立 WiFi 连接(DHCP 获取 IP 后)
↓
创建 NetworkAgent(WiFi, score=60)
↓
ConnectivityService.registerNetworkAgent(wifiAgent)
↓
rematchAllNetworksAndRequests()
├── WiFi: 60分 → 最高分
├── MOBILE: 50分
└── WiFi 成为默认网络
↓
更新路由:默认路由指向 wlan0
↓
更新 DNS:使用 WiFi 网络的 DNS 服务器
↓
发送 CONNECTIVITY_ACTION 广播
↓
移动数据降级(可能保持连接以便快速切换回来)
关键:移动数据降级后不会立即断开,而是保持连接以支持快速回切------这避免了因 WiFi 信号短暂波动导致的频繁切换。
5.3 Linger 机制
当一个高分网络可用时,低分网络不会立即断开,而是进入 Linger(暂缓)状态:
源码路径 : frameworks/base/services/core/java/com/android/server/ConnectivityService.java
java
private void handleLingerComplete(NetworkAgentInfo oldNetwork) {
if (oldNetwork == null) {
loge("Unknown NetworkAgentInfo in handleLingerComplete");
return;
}
oldNetwork.clearLingerState();
if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) {
teardownUnneededNetwork(oldNetwork);
} else {
updateCapabilities(oldNetwork.getCurrentScore(), oldNetwork,
oldNetwork.networkCapabilities);
}
}
关键设计 :
handleLingerComplete在 linger 超时后调用------如果旧网络仍有后台请求需要它,则保留但降级为后台网络;如果完全没有请求,则拆除网络。
Linger 的作用:给应用一些时间在新网络上建立连接,然后才断开旧网络,减少数据传输的中断时间。
六、默认网络的特殊性
默认网络是 Android 系统的特殊概念:未明确调用 bindProcessToNetwork() 的 Socket 自动走默认网络。
6.1 默认网络的切换流程
ConnectivityService.setDefaultNetwork(netId)
↓
NetworkManagementService.setDefaultNetwork(netId)
↓ 通过 NativeDaemonConnector 发送:
↓ "network default set <netId>"
↓
netd 的 NetworkController.setDefaultNetwork()
↓
更新路由表中的默认路由
↓
应用流量切换到新网络
关键 :默认网络切换通过
netd的network default set命令完成,netd负责更新fwmark规则和路由表,Java 层不直接操作路由。
6.2 默认网络与绑定网络的关系
java
// 绑定到 WiFi 的进程(如 VoIP 应用需要一直用 WiFi)
connectivityManager.bindProcessToNetwork(wifiNetwork);
// 此进程的所有 Socket 走 WiFi,不受默认网络切换影响
// 未绑定的进程
// 始终跟随默认网络,WiFi 断开后自动切到移动数据
关键 :
bindProcessToNetwork()通过setsockopt(SO_MARK)设置 Socket 的fwmark,内核根据fwmark选择路由表,实现进程级别的网络绑定。
七、LegacyTypeTracker --- 旧 API 兼容
Android 7 中,旧的 TYPE_WIFI / TYPE_MOBILE API 仍被广泛应用。LegacyTypeTracker 负责维护新老 API 的映射:
源码路径 : frameworks/base/services/core/java/com/android/server/ConnectivityService.java
java
private class LegacyTypeTracker {
private static final boolean DBG = true;
private static final boolean VDBG = false;
private final SparseArray<NetworkAgentInfo> mTypeMap = new SparseArray<>();
// 添加类型映射
public void add(int type, NetworkAgentInfo nai) { ... }
// 移除类型映射
public void remove(int type, NetworkAgentInfo nai) { ... }
// 获取指定类型的网络
public NetworkAgentInfo getNetworkForType(int type) { ... }
}
关键 :
mTypeMap是SparseArray<NetworkAgentInfo>,以int类型的TYPE_WIFI(1)/TYPE_MOBILE(0)为 key,值是对应的NetworkAgentInfo。
当调用旧的 API 如 getNetworkInfo(TYPE_WIFI) 时,ConnectivityService 通过 LegacyTypeTracker 找到对应的 NetworkAgent 并返回信息。
八、CONNECTIVITY_ACTION 广播
网络变化时 ConnectivityService 发送广播通知所有应用:
源码路径 : frameworks/base/services/core/java/com/android/server/ConnectivityService.java
java
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
if (info.isFailover()) {
intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
}
if (info.getReason() != null) {
intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
}
if (info.getExtraInfo() != null) {
intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
}
sendStickyBroadcast(intent);
关键设计 :使用 Sticky Broadcast 确保新注册的
BroadcastReceiver可以立刻收到最新的网络状态,而不需要等到下一次变化。同时通过FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT防止未启动完成的应用过早收到广播。
九、小结
本篇覆盖了 ConnectivityService 的核心机制:
| 机制 | 关键方法/数据 | 作用 |
|---|---|---|
| 网络代理管理 | NetworkAgentInfo 列表 |
跟踪所有活跃网络 |
| 评分与选择 | rematchAllNetworksAndRequests() |
决定默认网络 |
| Linger 暂缓 | handleLingerComplete() |
减少切换影响 |
| 旧 API 兼容 | LegacyTypeTracker |
TYPE_WIFI 等映射 |
| 广播通知 | CONNECTIVITY_ACTION |
通知应用网络变化 |
下一篇将深入 Framework 层的另外三大服务:NetworkManagementService(与 netd 通信)、NetworkPolicyManagerService(网络策略)、NetworkStatsService(流量统计)。