ConnectivityService框架

22 阅读9分钟

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;
    }

注册流程

  1. NetworkAgent 调用 register()
  2. 通过 ConnectivityManager 调用 registerNetworkAgent()
  3. ConnectivityService 创建 NetworkAgentInfo
  4. 添加到 mNetworkAgentInfos 集合
  5. 触发网络重新匹配 (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));
        }
    }

步骤

  1. 计算重新分配 (computeNetworkReassignment): 对每个请求找到最佳网络
  2. 应用重新分配 (applyNetworkReassignment): 更新满足关系
  3. 发出网络需求 (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()  │                  │
 │                          │ ─────────────────────────────────────>│
 │                          │                      │  (请求建立新网络) │

十一、关键特性

  1. 单线程模型:所有操作在 ConnectivityService Handler 线程执行,避免并发问题

  2. 懒惰评估:不会主动建立网络,只有在有请求时才建立

  3. 优雅降级:Linger 机制确保网络切换平滑

  4. 权限控制:严格的权限检查,不同 UID 看到不同的网络

  5. 性能优化

    • 增量 Rematch(仅重新匹配相关请求)
    • 批量处理回调
    • 避免不必要的网络创建/销毁

这就是 ConnectivityService 的完整框架!它是 Android 网络架构的大脑,协调所有网络和请求,确保应用始终连接到最佳网络。