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。
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。
public HandlerThread makeHandlerThread(@NonNull final String tag) {
return new HandlerThread(tag);
}正式构造函数把这个可替换的线程工厂用于服务线程:
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 | 消费对象 | 典型消息 |
|---|---|---|
InternalHandler | ConnectivityService 内部状态 | 网络请求、代理、超时、Netd 事件 |
NetworkStateTrackerHandler | NetworkAgent/NetworkMonitor | 能力、LinkProperties、连接状态 |
ConnectivityDiagnosticsHandler | 诊断回调 | 注册/注销、网络报告、data stall |
3. 内部消息
源码文件:packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
InternalHandler 把整数事件转换成强类型 payload,再调用 handle... 方法。状态实际保存在 NetworkRequestInfo、NetworkAgentInfo、请求表和网络映射中。
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,再决定消息是否失效、暂存或处理。
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 中消费。结构约束失败会断开并销毁网络,成功路径才写入声明 能力并更新网络评分。
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 和当前映射 判断消息是否属于活跃网络。
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。
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 和网络对象移除 延迟消息。
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。
@Override
public void onNat64PrefixEvent(final Nat64PrefixEventParcel event) {
mHandler.post(() -> handleNat64PrefixEvent(
event.netId, event.prefixOperation,
event.prefixAddress, event.prefixLength));
}Private DNS validation 将解析后的数据封装进 Message:
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,找不到就结束。
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。
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 退出后,未消费事件不会隐式恢复。
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 串行化。
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.javapackages/modules/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.javapackages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetInterfaceStateMachine.java
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 专题,避免让旧文章的抽象覆盖真实源码。
