ConnectivityService 框架详解
ConnectivityService 是 Android 网络架构的中央管理者,负责协调所有网络连接和请求。让我详细解析它的框架。
一、核心职责
* The primary responsibilities of this class are to:
* <ol>
* <li>Monitor network connections (Wi-Fi, GPRS, UMTS, etc.)</li>
* <li>Send broadcast intents when network connectivity changes</li>
* <li>Attempt to "fail over" to another network when connectivity to a network
* is lost</li>
* <li>Provide an API that allows applications to query the coarse-grained or fine-grained
* state of the available networks</li>
* <li>Provide an API that allows applications to request and select networks for their data
* traffic</li>
* </ol>
*/
二、核心数据结构
1. NetworkAgentInfo 集合 - 管理所有网络
// Tracks all NetworkAgents that are currently registered.
// NOTE: Only should be accessed on ConnectivityServiceThread, except dump().
private final ArraySet<NetworkAgentInfo> mNetworkAgentInfos = new ArraySet<>();
- 存储所有已注册的网络(WiFi、Cellular、Ethernet等)
- 每个
NetworkAgentInfo代表一个物理或虚拟网络 - 线程安全:仅在 ConnectivityService 线程访问
2. NetworkRequest 映射 - 管理所有网络请求
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
- 存储所有应用和系统的网络请求
- Key:
NetworkRequest- 请求本身 - Value:
NetworkRequestInfo- 请求的详细信息和满足状态
三、NetworkAgent 注册流程
/**
* Register this network agent with ConnectivityService.
*
* This method can only be called once per network agent.
*
* @return the Network associated with this network agent (which can also be obtained later
* by calling getNetwork() on this agent).
* @throws IllegalStateException thrown by the system server if this network agent is
* already registered.
*/
@NonNull
public Network register() {
if (VDBG) log("Registering NetworkAgent");
synchronized (mRegisterLock) {
if (mNetwork != null) {
throw new IllegalStateException("Agent already registered");
}
final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (mInitialConfiguration.localNetworkConfig == null) {
// Call registerNetworkAgent without localNetworkConfig argument to pass
// android.net.cts.NetworkAgentTest#testAgentStartsInConnecting in old cts
mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler),
new NetworkInfo(mInitialConfiguration.info),
mInitialConfiguration.properties, mInitialConfiguration.capabilities,
mInitialConfiguration.score, mInitialConfiguration.config, providerId);
} else {
mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler),
new NetworkInfo(mInitialConfiguration.info),
mInitialConfiguration.properties, mInitialConfiguration.capabilities,
mInitialConfiguration.localNetworkConfig, mInitialConfiguration.score,
mInitialConfiguration.config, providerId);
}
mInitialConfiguration = null; // All this memory can now be GC'd
}
return mNetwork;
}
注册流程:
- NetworkAgent 调用
register() - 通过 ConnectivityManager 调用
registerNetworkAgent() - ConnectivityService 创建
NetworkAgentInfo - 添加到
mNetworkAgentInfos集合 - 触发网络重新匹配 (
rematch)
四、网络请求处理
1. 请求注册
private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) {
handleRegisterNetworkRequests(Collections.singleton(nri));
}
private void handleRegisterNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
ensureRunningOnConnectivityServiceThread();
for (final NetworkRequestInfo nri : nris) {
mNetworkRequestInfoLogs.log("REGISTER " + nri);
checkNrisConsistency(nri);
for (final NetworkRequest req : nri.mRequests) {
mNetworkRequests.put(req, nri);
// TODO: Consider update signal strength for other types.
if (req.isListen()) {
for (final NetworkAgentInfo network : mNetworkAgentInfos) {
if (req.networkCapabilities.hasSignalStrength()
&& network.satisfiesImmutableCapabilitiesOf(req)) {
updateSignalStrengthThresholds(network, "REGISTER", req);
}
}
} else if (req.isRequest() && mNetworkRequestStateStatsMetrics != null) {
mNetworkRequestStateStatsMetrics.onNetworkRequestReceived(req);
}
}
// If this NRI has a satisfier already, it is replacing an older request that
// has been removed. Track it.
final NetworkRequest activeRequest = nri.getActiveRequest();
if (null != activeRequest) {
// If there is an active request, then for sure there is a satisfier.
nri.getSatisfier().addRequest(activeRequest);
}
if (shouldTrackUidsForBlockedStatusCallbacks()
&& isAppRequest(nri)
&& !nri.mUidTrackedForBlockedStatus) {
Log.wtf(TAG, "Registered nri is not tracked for sending blocked status: " + nri);
}
}
if (mFlags.noRematchAllRequestsOnRegister()) {
rematchNetworksAndRequests(nris);
2. 网络请求类型
switch (reqType) {
case TRACK_DEFAULT:
// If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities}
// is unused and will be replaced by ones appropriate for the UID (usually, the
// calling app). This allows callers to keep track of the default network.
networkCapabilities = copyDefaultNetworkCapabilitiesForUid(
defaultNc, asUid, callingUid, callingPackageName);
enforceAccessPermission();
break;
case TRACK_SYSTEM_DEFAULT:
enforceSettingsOrSetupWizardOrUseRestrictedNetworksPermission();
networkCapabilities = new NetworkCapabilities(defaultNc);
break;
case BACKGROUND_REQUEST:
enforceNetworkStackOrSettingsPermission();
// Fall-through since other checks are the same with normal requests.
case REQUEST:
networkCapabilities = new NetworkCapabilities(networkCapabilities);
enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
callingAttributionTag, callingUid);
// TODO: this is incorrect. We mark the request as metered or not depending on
// the state of the app when the request is filed, but we never change the
// request if the app changes network state. http://b/29964605
enforceMeteredApnPolicy(networkCapabilities);
maybeDisableLocalNetworkMatching(networkCapabilities, callingUid);
break;
case LISTEN_FOR_BEST:
enforceAccessPermission();
networkCapabilities = new NetworkCapabilities(networkCapabilities);
请求类型:
- REQUEST: 应用主动请求网络,可能导致网络建立
- LISTEN: 仅监听网络变化,不主动建立
- TRACK_DEFAULT: 跟踪默认网络
- TRACK_SYSTEM_DEFAULT: 跟踪系统默认网络
- BACKGROUND_REQUEST: 后台请求
- LISTEN_FOR_BEST: 监听最佳网络
五、核心算法:网络重新匹配 (Rematch)
这是 ConnectivityService 最关键的算法,决定哪个网络满足哪个请求。
1. 触发 Rematch 的场景
- 新网络注册
- 网络断开
- 网络评分变化
- 网络能力变化
- 新的网络请求注册
- 网络请求取消
2. Rematch 算法
/**
* This function is triggered when something can affect what network should satisfy what
* request, and it computes the network reassignment from the passed collection of requests to
* network match to the one that the system should now have. That data is encoded in an
* object that is a list of changes, each of them having an NRI, and old satisfier, and a new
* satisfier.
*
* After the reassignment is computed, it is applied to the state objects.
*
* @param networkRequests the nri objects to evaluate for possible network reassignment
* @return NetworkReassignment listing of proposed network assignment changes
*/
@NonNull
private NetworkReassignment computeNetworkReassignment(
@NonNull final Collection<NetworkRequestInfo> networkRequests) {
final NetworkReassignment changes = new NetworkReassignment();
// Gather the list of all relevant agents.
final ArrayList<NetworkAgentInfo> nais = new ArrayList<>();
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
nais.add(nai);
}
for (final NetworkRequestInfo nri : networkRequests) {
// Non-multilayer listen requests can be ignored.
if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
continue;
}
NetworkAgentInfo bestNetwork = null;
NetworkRequest bestRequest = null;
for (final NetworkRequest req : nri.mRequests) {
bestNetwork = mNetworkRanker.getBestNetwork(req, nais, nri.getSatisfier());
// Stop evaluating as the highest possible priority request is satisfied.
if (null != bestNetwork) {
bestRequest = req;
break;
}
}
if (null == bestNetwork && isDefaultBlocked(nri)) {
// Remove default networking if disallowed for managed default requests.
bestNetwork = mNoServiceNetwork;
}
if (nri.getSatisfier() != bestNetwork) {
// bestNetwork may be null if no network can satisfy this request.
changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
nri, nri.mActiveRequest, bestRequest, nri.getSatisfier(), bestNetwork));
}
}
return changes;
}
3. 完整的 Rematch 流程
/**
* Attempt to rematch all Networks with all NetworkRequests. This may result in Networks
* being disconnected.
*/
private void rematchAllNetworksAndRequests() {
rematchNetworksAndRequests(getNrisFromGlobalRequests());
}
/**
* Attempt to rematch all Networks with given NetworkRequests. This may result in Networks
* being disconnected.
*/
private void rematchNetworksAndRequests(
@NonNull final Set<NetworkRequestInfo> networkRequests) {
ensureRunningOnConnectivityServiceThread();
// TODO: This may be slow, and should be optimized.
final long start = SystemClock.elapsedRealtime();
final NetworkReassignment changes = computeNetworkReassignment(networkRequests);
final long computed = SystemClock.elapsedRealtime();
applyNetworkReassignment(changes, start);
final long applied = SystemClock.elapsedRealtime();
issueNetworkNeeds();
final long end = SystemClock.elapsedRealtime();
if (VDBG || DDBG) {
log(String.format("Rematched networks [computed %dms] [applied %dms] [issued %d]",
computed - start, applied - computed, end - applied));
log(changes.debugString());
} else if (DBG) {
// Shorter form, only one line of log
log(String.format("%s [c %d] [a %d] [i %d]", changes.toString(),
computed - start, applied - computed, end - applied));
}
}
步骤:
- 计算重新分配 (
computeNetworkReassignment): 对每个请求找到最佳网络 - 应用重新分配 (
applyNetworkReassignment): 更新满足关系 - 发出网络需求 (
issueNetworkNeeds): 通知 NetworkProvider
六、关键组件
1. NetworkRanker - 网络排名器
- 根据策略选择最佳网络
- 详见之前的"网络评分机制"分析
2. DnsManager - DNS 管理
- Private DNS 配置
- DNS 验证
3. MultinetworkPolicyTracker - 多网络策略
- "避免坏 WiFi" 配置
- 多网络同时激活策略
4. PermissionMonitor - 权限监控
- 监控应用权限变化
- INTERNET 权限检查
5. NetworkNotificationManager - 通知管理
- 显示网络状态通知
- Captive Portal 通知
- 部分连接通知
6. LingerMonitor - Linger 监控
- 实现网络保活机制
- 监控网络切换
七、Linger 机制
// Default to 30s linger time-out, and 5s for nascent network. Modifiable only for testing.
private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
private static final int DEFAULT_NASCENT_DELAY_MS = 5_000;
Linger 状态:
- Nascent (新生): 网络刚连接,还未被使用,保留 5 秒
- Lingering (徘徊): 网络失去所有请求但仍保持连接 30 秒
- 目的:避免频繁切换网络,给替代网络时间验证
八、事件驱动架构
ConnectivityService 使用 Handler 机制处理异步事件:
/**
* used internally to clear a wakelock when transitioning
* from one net to another. Clear happens when we get a new
* network - EVENT_EXPIRE_NET_TRANSITION_WAKELOCK happens
* after a timeout if no network is found (typically 1 min).
*/
private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8;
/**
* used internally to reload global proxy settings
*/
private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9;
/**
* PAC manager has received new port.
*/
private static final int EVENT_PAC_PROXY_HAS_CHANGED = 16;
/**
* used internally when registering NetworkProviders
* obj = NetworkProviderInfo
*/
private static final int EVENT_REGISTER_NETWORK_PROVIDER = 17;
/**
* used internally when registering NetworkAgents
* obj = Messenger
*/
private static final int EVENT_REGISTER_NETWORK_AGENT = 18;
/**
* used to add a network request
* includes a NetworkRequestInfo
*/
private static final int EVENT_REGISTER_NETWORK_REQUEST = 19;
/**
* indicates a timeout period is over - check if we had a network yet or not
* and if not, call the timeout callback (but leave the request live until they
* cancel it.
* includes a NetworkRequestInfo
*/
private static final int EVENT_TIMEOUT_NETWORK_REQUEST = 20;
/**
* used to add a network listener - no request
* includes a NetworkRequestInfo
*/
private static final int EVENT_REGISTER_NETWORK_LISTENER = 21;
/**
* used to remove a network request, either a listener or a real request
* arg1 = UID of caller
* obj = NetworkRequest
*/
private static final int EVENT_RELEASE_NETWORK_REQUEST = 22;
/**
* used internally when registering NetworkProviders
* obj = Messenger
*/
private static final int EVENT_UNREGISTER_NETWORK_PROVIDER = 23;
/**
* used internally to expire a wakelock when transitioning
* from one net to another. Expire happens when we fail to find
* a new network (typically after 1 minute) -
* EVENT_CLEAR_NET_TRANSITION_WAKELOCK happens if we had found
* a replacement network.
*/
private static final int EVENT_EXPIRE_NET_TRANSITION_WAKELOCK = 24;
/**
* used to add a network request with a pending intent
* obj = NetworkRequestInfo
*/
private static final int EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT = 26;
/**
* used to remove a pending intent and its associated network request.
* arg1 = UID of caller
* obj = PendingIntent
*/
private static final int EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT = 27;
/**
* used to specify whether a network should be used even if unvalidated.
* arg1 = whether to accept the network if it's unvalidated (1 or 0)
* arg2 = whether to remember this choice in the future (1 or 0)
* obj = network
*/
private static final int EVENT_SET_ACCEPT_UNVALIDATED = 28;
/**
* used internally to (re)configure always-on networks.
*/
private static final int EVENT_CONFIGURE_ALWAYS_ON_NETWORKS = 30;
/**
* used to add a network listener with a pending intent
* obj = NetworkRequestInfo
*/
private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31;
/**
* used to specify whether a network should not be penalized when it becomes unvalidated.
*/
private static final int EVENT_SET_AVOID_UNVALIDATED = 35;
/**
* used to handle reported network connectivity. May trigger revalidation of a network.
*/
private static final int EVENT_REPORT_NETWORK_CONNECTIVITY = 36;
// Handle changes in Private DNS settings.
private static final int EVENT_PRIVATE_DNS_SETTINGS_CHANGED = 37;
// Handle private DNS validation status updates.
private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38;
/**
* Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
* been tested.
* obj = {@link NetworkTestedResults} representing information sent from NetworkMonitor.
* data = PersistableBundle of extras passed from NetworkMonitor. If {@link
* NetworkMonitorCallbacks#notifyNetworkTested} is called, this will be null.
*/
private static final int EVENT_NETWORK_TESTED = 41;
/**
* Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the private DNS
* config was resolved.
* obj = PrivateDnsConfig
* arg2 = netid
*/
private static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = 42;
/**
* Request ConnectivityService display provisioning notification.
* arg1 = Whether to make the notification visible.
* arg2 = NetID.
* obj = Intent to be launched when notification selected by user, null if !arg1.
*/
private static final int EVENT_PROVISIONING_NOTIFICATION = 43;
/**
* Used to specify whether a network should be used even if connectivity is partial.
* arg1 = whether to accept the network if its connectivity is partial (1 for true or 0 for
* false)
* arg2 = whether to remember this choice in the future (1 for true or 0 for false)
* obj = network
*/
private static final int EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY = 44;
/**
* Event for NetworkMonitor to inform ConnectivityService that the probe status has changed.
* Both of the arguments are bitmasks, and the value of bits come from
* INetworkMonitor.NETWORK_VALIDATION_PROBE_*.
* arg1 = unused
* arg2 = netId
* obj = A Pair of integers: the bitmasks of, respectively, completed and successful probes.
*/
public static final int EVENT_PROBE_STATUS_CHANGED = 45;
九、ConnectivityService 架构图
┌─────────────────────────────────────────────────────────────────────┐
│ ConnectivityService │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Handler (单线程处理) │ │
│ │ • EVENT_REGISTER_NETWORK_AGENT │ │
│ │ • EVENT_REGISTER_NETWORK_REQUEST │ │
│ │ • EVENT_NETWORK_TESTED │ │
│ │ • EVENT_PRIVATE_DNS_VALIDATION_UPDATE │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────┐ ┌──────────────────────────────────┐ │
│ │ mNetworkAgentInfos │ │ mNetworkRequests │ │
│ │ (所有网络) │ │ (所有请求) │ │
│ │ • WiFi │ │ • App 请求 │ │
│ │ • Cellular │ │ • 系统请求 │ │
│ │ • VPN │ │ • 监听器 │ │
│ │ • Ethernet │ │ • 默认网络跟踪 │ │
│ └──────────────────────┘ └──────────────────────────────────┘ │
│ │ │ │
│ └──────────────┬───────────────┘ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ rematchNetworksAndRequests() │ │
│ │ 1. 计算重新分配 (computeNetworkReassignment) │ │
│ │ • 使用 NetworkRanker 为每个请求找最佳网络 │ │
│ │ 2. 应用重新分配 (applyNetworkReassignment) │ │
│ │ • 更新 NetworkAgentInfo 的请求列表 │ │
│ │ • 更新 NetworkRequestInfo 的满足者 │ │
│ │ 3. 发出网络需求 (issueNetworkNeeds) │ │
│ │ • 通知 NetworkProvider 需要新网络 │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────── 核心组件 ────────────────────────────────┐ │
│ │ • NetworkRanker - 网络排名 │ │
│ │ • DnsManager - DNS 管理 │ │
│ │ • LingerMonitor - Linger 监控 │ │
│ │ • PermissionMonitor - 权限监控 │ │
│ │ • MultinetworkPolicyTracker - 多网络策略 │ │
│ │ • NetworkNotificationManager - 通知管理 │ │
│ │ • RoutingCoordinatorService - 路由协调 │ │
│ └──────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
▲ │
│ 注册/更新 │ 回调
│ ▼
┌────────────────────────────────┐ ┌──────────────────────────────┐
│ NetworkAgent │ │ 应用 / 系统服务 │
│ • TelephonyNetworkAgent │ │ • NetworkCallback │
│ • WifiNetworkAgent │ │ • NetworkRequest │
│ • VpnNetworkAgent │ │ • ConnectivityManager │
└────────────────────────────────┘ └──────────────────────────────┘
十、关键流程时序
1. 网络连接流程
NetworkAgent ConnectivityService NetworkMonitor App
│ │ │ │
│ register() │ │ │
├───────────────────────>│ │ │
│ │ 创建 NetworkAgentInfo │ │
│ │ │ │
│ markConnected() │ │ │
├───────────────────────>│ 触发验证 │ │
│ ├─────────────────────────>│ │
│ │ │ HTTP/HTTPS探测 │
│ │ rematchNetworksAndRequests() │ │
│ │ (找到满足的请求) │ │
│ │ │ │
│ │ onAvailable() │ │
│ ├────────────────────────────────────────>│
│ │ │ onValidated │
│ │<─────────────────────────┤ │
│ │ 更新能力: VALIDATED │ │
│ ├────────────────────────────────────────>│
│ │ onCapabilitiesChanged() │ │
2. 网络请求流程
App ConnectivityService NetworkRanker NetworkAgent
│ │ │ │
│ requestNetwork() │ │ │
├─────────────────────────>│ │ │
│ │ 创建 NRI │ │
│ │ rematchNetworks() │ │
│ ├─────────────────────>│ │
│ │ getBestNetwork() │ │
│ │<─────────────────────┤ │
│ │ │ │
│ 情况1: 有满足的网络 │ │ │
│<─────────────────────────┤ onAvailable() │ │
│ │ │ │
│ 情况2: 无满足的网络 │ │ │
│ │ issueNetworkNeeds() │ │
│ │ ─────────────────────────────────────>│
│ │ │ (请求建立新网络) │
十一、关键特性
-
单线程模型:所有操作在 ConnectivityService Handler 线程执行,避免并发问题
-
懒惰评估:不会主动建立网络,只有在有请求时才建立
-
优雅降级:Linger 机制确保网络切换平滑
-
权限控制:严格的权限检查,不同 UID 看到不同的网络
-
性能优化:
- 增量 Rematch(仅重新匹配相关请求)
- 批量处理回调
- 避免不必要的网络创建/销毁
这就是 ConnectivityService 的完整框架!它是 Android 网络架构的大脑,协调所有网络和请求,确保应用始终连接到最佳网络。