Skip to content

ConnectivityService Handler 状态

追踪 ConnectivityService 的 HandlerThread、InternalHandler、NetworkStateTrackerHandler 和网络事件串行化边界。

基于android-17.0.0_r1
AndroidConnectivityServiceHandlerNetworkAgent源码阅读

ConnectivityService Handler 状态 ​

先纠正一个容易误读的前提:在 android-17.0.0_r1 的当前 Connectivity 模块中, ConnectivityService 不继承 com.android.internal.util.StateMachine。它使用一个 ConnectivityServiceThread、一个处理内部事件的 InternalHandler,以及同一 Looper 上的 NetworkStateTrackerHandler 和 ConnectivityDiagnosticsHandler。归档文章把旧式 StateMachine 结构套到当前源码上,不能作为本版本事实来源。

本文面向已经读过 AMS Handler 分流、HandlerThread 生命周期、 消息延迟边界 和 ActivityThread.H 主线程 的读者。本文不介绍通用状态机设计,也不把 EthernetInterfaceStateMachine 或旧版 Wi-Fi 状态机移植成 ConnectivityService 的实现;只追踪当前 ConnectivityService.java 中 Handler 如何接收 NetworkAgent/NetworkMonitor 事件、在对象已销毁时丢弃消息、安排评价超时,以及把 Binder/Netd 回调串行化到同一 Looper。

读完后,读者应能确认当前版本是否真的存在 StateMachine,定位 ConnectivityService 的三个 Handler owner,解释 NetworkAgent 事件为何要先检查 NetworkAgentInfo 生命周期,并判断 EVENT_INITIAL_EVALUATION_TIMEOUT 的延迟、取消和失效路径。

1. 版本核对 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

当前实现的类声明是 ConnectivityService extends IConnectivityManager.Stub,没有继承 StateMachine。源码导入了 Handler 和 HandlerThread,但没有把 ConnectivityService 本身建模为层级 StateMachine。

java
public class ConnectivityService extends IConnectivityManager.Stub
        implements BroadcastReceiveHelper.Delegate {
    protected final HandlerThread mHandlerThread;
    final private InternalHandler mHandler;
    final private NetworkStateTrackerHandler mTrackerHandler;
    final ConnectivityDiagnosticsHandler mConnectivityDiagnosticsHandler;
}

如果先从归档文章的“StateMachine”标题开始,容易把不存在的 transitionTo()、父状态栈和 deferMessage() 写进当前版本。教材应先以固定 release 的文件和符号判断对象真实存在。

2. 线程建立 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

依赖对象提供 makeHandlerThread()。正式构造函数创建并启动 ConnectivityServiceThread, 再把三个 Handler 都绑定到同一个 Looper。

java
public HandlerThread makeHandlerThread(@NonNull final String tag) {
    return new HandlerThread(tag);
}

正式构造函数把这个可替换的线程工厂用于服务线程:

java
mHandlerThread = mDeps.makeHandlerThread("ConnectivityServiceThread");
mHandlerThread.start();
mHandler = new InternalHandler(mHandlerThread.getLooper());
mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
mConnectivityDiagnosticsHandler =
        new ConnectivityDiagnosticsHandler(mHandlerThread.getLooper());

三个 Handler 共享一个 Looper,因此它们之间没有并行执行;拆分 Handler 的作用是隔离消息 协议,而不是获得三条线程。

Handler消费对象典型消息
InternalHandlerConnectivityService 内部状态网络请求、代理、超时、Netd 事件
NetworkStateTrackerHandlerNetworkAgent/NetworkMonitor能力、LinkProperties、连接状态
ConnectivityDiagnosticsHandler诊断回调注册/注销、网络报告、data stall

3. 内部消息 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

InternalHandler 把整数事件转换成强类型 payload,再调用 handle... 方法。状态实际保存在 NetworkRequestInfo、NetworkAgentInfo、请求表和网络映射中。

java
private class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case EVENT_REGISTER_NETWORK_AGENT: {
                final Pair<NetworkAgentInfo, INetworkMonitor> arg =
                        (Pair<NetworkAgentInfo, INetworkMonitor>) msg.obj;
                handleRegisterNetworkAgent(arg.first, arg.second);
                break;
            }
            case EVENT_TIMEOUT_NETWORK_REQUEST:
                handleTimedOutNetworkRequest((NetworkRequestInfo) msg.obj);
                break;
            case EVENT_INITIAL_EVALUATION_TIMEOUT:
                handleInitialEvaluationTimeout((Network) msg.obj);
                break;
        }
    }
}

Handler 只负责把消息交给当前线程,不能代替 payload 对象的生命周期检查。

4. Agent 事件 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

NetworkStateTrackerHandler 的注释写明它必须是无状态的,因为网络状态随消息到达时刻变化。 它先取出 NetworkAgentInfo,再决定消息是否失效、暂存或处理。

java
private void maybeHandleNetworkAgentMessage(Message msg) {
    final Pair<NetworkAgentInfo, Object> arg =
            (Pair<NetworkAgentInfo, Object>) msg.obj;
    final NetworkAgentInfo nai = arg.first;

    if (nai.isDestroyed() && !isDisconnectRequest(msg)) {
        log("Message " + eventName(msg.what)
                + " from destroyed agent with netId " + nai.network.netId);
        return;
    }
    if (mQueueNetworkAgentEventsInSystemServer && nai.maybeEnqueueMessage(msg)) {
        return;
    }
    if (!mNetworkAgentInfos.contains(nai)) {
        return;
    }
    // 进入具体事件分支
}

已销毁 agent 的非 disconnect 事件会被丢弃;注册尚未完成时,事件可由 NetworkAgentInfo 按顺序暂存。两者都是业务生命周期检查,不是 StateMachine 的父状态或 deferred message。

5. 能力更新 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

能力更新在同一 Handler Looper 中消费。结构约束失败会断开并销毁网络,成功路径才写入声明 能力并更新网络评分。

java
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
    final NetworkCapabilities proposed = (NetworkCapabilities) arg.second;
    if (!nai.respectsNcStructuralConstraints(proposed)) {
        Log.wtf(TAG, "Agent " + nai + " violates nc structural constraints");
        disconnectAndDestroyNetwork(nai);
        return;
    }
    nai.setDeclaredCapabilities(proposed);
    final NetworkCapabilities sanitized =
            nai.getDeclaredCapabilitiesSanitized(mCarrierPrivilegeAuthenticator);
    maybeUpdateWifiRoamTimestamp(nai, sanitized);
    updateCapabilities(nai.getScore(), nai, sanitized);
    break;
}

这里的状态变化是 NetworkAgentInfo 字段和 ConnectivityService 网络映射的变化,不是 transitionTo()。失败路径直接改变网络生命周期,不能只返回“未处理”。

6. 网络属性 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

LinkProperties、NetworkInfo 和 NetworkScore 由同一 NetworkStateTrackerHandler 顺序处理。 顺序来自一个 Looper,但不同 NetworkAgent 的消息仍可能交错;代码通过 payload 和当前映射 判断消息是否属于活跃网络。

java
case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
    final LinkProperties newLp = (LinkProperties) arg.second;
    processLinkPropertiesFromAgent(nai, newLp);
    handleUpdateLinkProperties(nai, newLp);
    break;
}
case NetworkAgent.EVENT_NETWORK_INFO_CHANGED:
    updateNetworkInfo(nai, (NetworkInfo) arg.second);
    break;
case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED:
    updateNetworkScore(nai, (NetworkScore) arg.second);
    break;

“同一 Handler 串行”只保证这些 case 不同时运行,不保证网络事件按设备时间戳排序。

7. 评价超时 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

网络连接后,如果还没有收到验证结果,Dependencies 会把 EVENT_INITIAL_EVALUATION_TIMEOUT 作为延迟消息发送给指定 Handler;ConnectivityService 使用自己的 mHandler。

java
public void scheduleEvaluationTimeout(@NonNull Handler handler,
        @NonNull final Network network, final long delayMs) {
    handler.sendMessageDelayed(
            handler.obtainMessage(EVENT_INITIAL_EVALUATION_TIMEOUT, network), delayMs);
}

public void scheduleEvaluationTimeout(@NonNull final Network network, final long delayMs) {
    mDeps.scheduleEvaluationTimeout(mHandler, network, delayMs);
}

延迟消息的 obj 是 Network,不是 NetworkAgentInfo。到期后处理方法会重新查找当前 网络状态;网络已验证、销毁或不存在时,旧 timeout 不能被当作当前事实。

8. 超时取消 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

当网络在 timeout 到达前完成验证或被销毁,ConnectivityService 按 what 和网络对象移除 延迟消息。

java
if (nai.isValidated()) {
    mHandler.removeMessages(EVENT_INITIAL_EVALUATION_TIMEOUT, nai.network);
    handleInitialEvaluationTimeout(nai.network);
}

取消是 ConnectivityService 业务代码维护的协议:发送者和取消者必须使用相同的 what/obj 匹配规则,否则旧 timeout 仍可能到达。

9. 外部事件 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

Netd unsolicited callback 可能在 Binder 线程到达,但需要统一处理的事件会投递到 mHandler。

java
@Override
public void onNat64PrefixEvent(final Nat64PrefixEventParcel event) {
    mHandler.post(() -> handleNat64PrefixEvent(
            event.netId, event.prefixOperation,
            event.prefixAddress, event.prefixLength));
}

Private DNS validation 将解析后的数据封装进 Message:

java
mHandler.sendMessage(mHandler.obtainMessage(
        EVENT_PRIVATE_DNS_VALIDATION_UPDATE,
        new PrivateDnsValidationUpdate(
                event.netId, address, event.hostname, event.validation)));

这些入口把外部线程事件转换为服务线程上的顺序处理;它们不构成层级状态转换。

10. 诊断分流 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

ConnectivityDiagnosticsHandler 与其他 Handler 共享 Looper,但只处理诊断回调协议。消息 消费时重新查找 NetworkAgentInfo,找不到就结束。

java
class ConnectivityDiagnosticsHandler extends Handler {
    private ConnectivityDiagnosticsHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK:
                handleRegisterConnectivityDiagnosticsCallback(
                        (ConnectivityDiagnosticsCallbackInfo) msg.obj);
                break;
            case EVENT_DATA_STALL_SUSPECTED: {
                final NetworkAgentInfo nai =
                        getNetworkAgentInfoForNetId(msg.arg2);
                if (nai == null) break;
                final Pair<Long, PersistableBundle> arg =
                        (Pair<Long, PersistableBundle>) msg.obj;
                handleDataStallSuspected(nai, arg.first, msg.arg1, arg.second);
                break;
            }
            default:
                Log.e(mTag, "Unrecognized event in ConnectivityDiagnostics: " + msg.what);
        }
    }
}

Handler 分流是协议隔离,不是线程隔离;三个 Handler 的 callback 仍排在同一 Looper 队列中。

11. Keepalive 事件 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

InternalHandler 消费 keepalive 消息时,先通过 Binder 找对象和网络;注销后迟到的消息会直接 返回,避免重新启动不存在的 keepalive。

java
case AutomaticOnOffKeepaliveTracker.CMD_MONITOR_AUTOMATIC_KEEPALIVE: {
    final AutomaticOnOffKeepalive ki =
            mKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj);
    if (ki == null) return;
    final Network network = ki.getNetwork();
    if (!anyNetworkAgentInfo(nai -> nai.network.equals(network))) return;
    mKeepaliveTracker.handleMonitorAutomaticKeepalive(
            ki, ki.getUnderpinnedNetwork().netId);
    break;
}

这和 NetworkAgentInfo.isDestroyed() 检查是同一种边界:队列保存过去创建的 payload,业务 状态必须在消费瞬间重新确认。

12. 关闭路径 ​

源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

当前 ConnectivityService 没有 StateMachine 的 quitNow();线程生命周期由 HandlerThread owner 和服务停止流程管理。HandlerThread 退出后,未消费事件不会隐式恢复。

java
mHandlerThread.start();
// mHandler、mTrackerHandler 和诊断 Handler 都绑定该线程 Looper

因此当前版本的清理必须逐个检查网络 agent、回调、监听器、Handler 消息和线程 owner,不能 套用旧 StateMachine 的统一退出状态。

13. 测试输入 ​

源码文件:packages/modules/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java

Connectivity 模块通过 Dependencies.makeHandlerThread() 允许测试注入 HandlerThread 和依赖, 再推进 Looper 检查事件消费。测试重点是 payload 生命周期和 Handler 串行化。

java
public HandlerThread makeHandlerThread(@NonNull final String tag) {
    return new HandlerThread(tag);
}

可执行验证应覆盖:未注册 agent 的更新、已销毁 agent 的非 disconnect 更新、以及评价 timeout 前完成验证。关键断言分别是“事件被忽略/暂存”“不再修改网络状态”“旧 timeout 不再改变 状态”。这些不能外推为真实设备的网络时延或 Input/Netd 事件完整性。

14. 复查命令 ​

源码文件:

  • packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
  • packages/modules/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java
  • packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetInterfaceStateMachine.java
bash
rg -n "class ConnectivityService|mHandlerThread|InternalHandler|NetworkStateTrackerHandler|ConnectivityDiagnosticsHandler" \
  packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

rg -n "EVENT_INITIAL_EVALUATION_TIMEOUT|scheduleEvaluationTimeout|removeMessages|handleInitialEvaluationTimeout" \
  packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

rg -n "isDestroyed|maybeEnqueueMessage|EVENT_NETWORK_CAPABILITIES_CHANGED|EVENT_NETWORK_INFO_CHANGED" \
  packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java

rg -n "makeHandlerThread|ConnectivityServiceTest|NetworkAgent" \
  packages/modules/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java

如果要研究真正的层级 StateMachine,应另外阅读 EthernetInterfaceStateMachine.java,不要把它 的父子状态逻辑倒灌回 ConnectivityService。当前主线是“HandlerThread + 多 Handler + payload 生命周期检查”。

15. 适用边界 ​

当前版本 ConnectivityService 的 Handler 设计适合把 Binder、Netd、NetworkMonitor 和 NetworkAgent 事件串行化到一个服务线程,并在消费时重新验证网络对象生命周期。它不提供层级 状态自动转换、消息 exactly-once、设备事件时间排序或线程退出后的恢复。

排查网络事件未生效时,应按顺序检查:消息进入哪个 Handler,NetworkAgentInfo 是否已注册或 销毁,事件是否被暂存,timeout 是否仍存在,处理方法是否更新了正确的 network map,以及 HandlerThread 是否仍然存活。先确认当前 release 的实际类结构,再决定是否需要 StateMachine 专题,避免让旧文章的抽象覆盖真实源码。