Framework层(上)—ConnectivityService核心机制)
系列目录第一篇全景图与调用链路概览 | 第二篇内核层—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// SystemServer.startOtherServices() 中connectivitynewConnectivityService(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.javapublicclassNetworkAgentInfoimplementsComparableNetworkAgentInfo{publicNetworkInfonetworkInfo;// 网络信息类型、状态等publicfinalNetworknetwork;// Network 对象publicLinkPropertieslinkProperties;// IP、网关、DNS 等publicNetworkCapabilitiesnetworkCapabilities;// 网络能力publicfinalNetworkMonitornetworkMonitor;// 网络连通性探测器publicfinalNetworkMiscnetworkMisc;// 网络杂项配置publicbooleancreated;// 是否已在 netd 创建publicbooleaneverConnected;// 是否曾经连接过publicbooleaneverValidated;// 是否曾经验证通过publicbooleanlastValidated;// 最后验证结果publicbooleanavoidUnvalidated;// 是否避免未验证网络// ...}关键设计network字段声明为final保证每个NetworkAgentInfo的Network对象在构造后不再变化created和everConnected是 sticky bit一旦设置就不会清除。3.2 NetworkCapabilities源码路径frameworks/base/core/java/android/net/NetworkCapabilities.java描述网络能做什么不能做什么。publicfinalclassNetworkCapabilities{// Transport 类型publicstaticfinalintTRANSPORT_CELLULAR0;publicstaticfinalintTRANSPORT_WIFI1;publicstaticfinalintTRANSPORT_ETHERNET3;publicstaticfinalintTRANSPORT_VPN4;// ...// 能力定义publicstaticfinalintNET_CAPABILITY_INTERNET12;// 能上互联网publicstaticfinalintNET_CAPABILITY_NOT_METERED11;// 不计流量publicstaticfinalintNET_CAPABILITY_VALIDATED16;// 已验证可上网// ...}关键设计TRANSPORT_*描述网络的传输介质NET_CAPABILITY_*描述网络的能力两者独立判断——一个 VPN 可以同时具备TRANSPORT_VPN和NET_CAPABILITY_INTERNET。3.3 NetworkRequest源码路径frameworks/base/core/java/android/net/NetworkRequest.java应用通过NetworkRequest描述它需要的网络类型publicclassNetworkRequest{publicNetworkCapabilitiesnetworkCapabilities;// 请求的网络能力publicintlegacyType;// 旧 API 中的 TYPE_WIFI 等publicintrequestId;// 唯一请求 ID}关键legacyType用于兼容旧的TYPE_WIFI/TYPE_MOBILEAPI新代码应使用networkCapabilities描述需求。应用构建请求的示例NetworkRequestrequestnewNetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();connectivityManager.requestNetwork(request,callback);关键Builder模式的链式调用让应用可以精确描述网络需求ConnectivityService根据这些约束匹配最合适的网络。四、网络评分与选择机制4.1 整体流程ConnectivityService的核心算法是网络评分与匹配。当有新网络出现或有新请求时触发条件新网络建立 / 新请求到达 / 网络断开 ↓ rematchAllNetworksAndRequests() ↓ 对每个 NetworkRequest遍历所有 NetworkAgent ↓ 找到评分最高、能力匹配的 NetworkAgent ↓ 更新默认网络如果最高分网络变化 ↓ 通知 NetworkCallbackonAvailable / onLost / onCapabilitiesChanged关键rematchAllNetworksAndRequests()是重匹配的入口每次网络拓扑变化时调用确保默认网络始终是评分最高且满足条件的那一个。4.2 evalRequest — 评分核心逻辑源码路径frameworks/base/core/java/android/net/NetworkFactory.javaprivatevoidevalRequest(NetworkRequestInfon){if(n.requestedfalsen.scoremScoren.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter)acceptRequest(n.request,n.score)){needNetworkFor(n.request,n.score);n.requestedtrue;}elseif(n.requestedtrue(n.scoremScore||n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter)false||acceptRequest(n.request,n.score)false)){releaseNetworkFor(n.request);n.requestedfalse;}}关键设计evalRequest通过比较n.score与当前工厂的mScore决定是否需要此网络——请求的评分低于工厂评分时工厂接手请求评分高于工厂评分时释放网络交给更高评分的工厂。每个NetworkFactory根据自身类型给出基础评分网络类型基础评分说明以太网70有线最稳定WiFi60无线局域网移动数据4G50蜂窝网络蓝牙共享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 (score70) ↓ 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 可用(score50) └── 移动数据成为默认网络 ↓ 更新默认网络updateDnses / addDefaultRoute ↓ 发送 CONNECTIVITY_ACTION 广播 ↓ 通知所有 NetworkCallback: onAvailable(MOBILE)关键切换过程中updateDnses和addDefaultRoute先执行确保新网络的 DNS 和路由就绪后才发送广播避免应用收到广播后发起请求时网络尚未配置完成。5.2 新 WiFi 连接从移动数据切换WifiStateMachine 建立 WiFi 连接DHCP 获取 IP 后 ↓ 创建 NetworkAgent(WiFi, score60) ↓ 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.javaprivatevoidhandleLingerComplete(NetworkAgentInfooldNetwork){if(oldNetworknull){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 默认网络与绑定网络的关系// 绑定到 WiFi 的进程如 VoIP 应用需要一直用 WiFiconnectivityManager.bindProcessToNetwork(wifiNetwork);// 此进程的所有 Socket 走 WiFi不受默认网络切换影响// 未绑定的进程// 始终跟随默认网络WiFi 断开后自动切到移动数据关键bindProcessToNetwork()通过setsockopt(SO_MARK)设置 Socket 的fwmark内核根据fwmark选择路由表实现进程级别的网络绑定。七、LegacyTypeTracker — 旧 API 兼容Android 7 中旧的TYPE_WIFI/TYPE_MOBILEAPI 仍被广泛应用。LegacyTypeTracker负责维护新老 API 的映射源码路径frameworks/base/services/core/java/com/android/server/ConnectivityService.javaprivateclassLegacyTypeTracker{privatestaticfinalbooleanDBGtrue;privatestaticfinalbooleanVDBGfalse;privatefinalSparseArrayNetworkAgentInfomTypeMapnewSparseArray();// 添加类型映射publicvoidadd(inttype,NetworkAgentInfonai){...}// 移除类型映射publicvoidremove(inttype,NetworkAgentInfonai){...}// 获取指定类型的网络publicNetworkAgentInfogetNetworkForType(inttype){...}}关键mTypeMap是SparseArrayNetworkAgentInfo以int类型的TYPE_WIFI1/TYPE_MOBILE0为 key值是对应的NetworkAgentInfo。当调用旧的 API 如getNetworkInfo(TYPE_WIFI)时ConnectivityService通过LegacyTypeTracker找到对应的NetworkAgent并返回信息。八、CONNECTIVITY_ACTION 广播网络变化时ConnectivityService发送广播通知所有应用源码路径frameworks/base/services/core/java/com/android/server/ConnectivityService.javaIntentintentnewIntent(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 兼容LegacyTypeTrackerTYPE_WIFI等映射广播通知CONNECTIVITY_ACTION通知应用网络变化下一篇将深入 Framework 层的另外三大服务NetworkManagementService与 netd 通信、NetworkPolicyManagerService网络策略、NetworkStatsService流量统计。