在 ConnectivityService 中负责配置,由 updateLinkProperties 来完成:
private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties newLp,
LinkProperties oldLp) {
int netId = networkAgent.network.netId;
// The NetworkAgent does not know whether clatd is running on its network or not, or whether
// a NAT64 prefix was discovered by the DNS resolver. Before we do anything else, make sure
// the LinkProperties for the network are accurate.
networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities,
networkAgent.networkInfo.getType());
// update filtering rules, need to happen after the interface update so netd knows about the
// new interface (the interface name -> index map becomes initialized)
updateVpnFiltering(newLp, oldLp, networkAgent);
updateMtu(newLp, oldLp);
// TODO - figure out what to do for clat
// for (LinkProperties lp : newLp.getStackedLinks()) {
// updateMtu(lp, null);
// }
if (isDefaultNetwork(networkAgent)) {
updateTcpBufferSizes(newLp.getTcpBufferSizes());
}
updateRoutes(newLp, oldLp, netId);
updateDnses(newLp, oldLp, netId);
// Make sure LinkProperties represents the latest private DNS status.
// This does not need to be done before updateDnses because the
// LinkProperties are not the source of the private DNS configuration.
// updateDnses will fetch the private DNS configuration from DnsManager.
mDnsManager.updatePrivateDnsStatus(netId, newLp);
if (isDefaultNetwork(networkAgent)) {
handleApplyDefaultProxy(newLp.getHttpProxy());
} else {
updateProxy(newLp, oldLp);
}
updateWakeOnLan(newLp);
// Captive portal data is obtained from NetworkMonitor and stored in NetworkAgentInfo,
// it is not contained in LinkProperties sent from NetworkAgents so needs to be merged here.
newLp.setCaptivePortalData(networkAgent.captivePortalData);
// TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) {
synchronized (networkAgent) {
networkAgent.linkProperties = newLp;
}
// Start or stop DNS64 detection and 464xlat according to network state.
networkAgent.clatd.update();
notifyIfacesChangedForNetworkStats();
networkAgent.networkMonitor().notifyLinkPropertiesChanged(
new LinkProperties(newLp, true /* parcelSensitiveFields */));
if (networkAgent.everConnected) {
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
}
mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent);
}
上述函数里面调用了各种 updateXXX 操作实现了更新过程,其实际调用者为 handleUpdateLinkProperties:
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
ensureRunningOnConnectivityServiceThread();
if (getNetworkAgentInfoForNetId(nai.network.netId) != nai) {
// Ignore updates for disconnected networks
return;
}
if (VDBG || DDBG) {
log("Update of LinkProperties for " + nai.toShortString()
+ "; created=" + nai.created
+ "; everConnected=" + nai.everConnected);
}
// TODO: eliminate this defensive copy after confirming that updateLinkProperties does not
// modify its oldLp parameter.
updateLinkProperties(nai, newLp, new LinkProperties(nai.linkProperties));
}
处理过程在 内部类 NetworkStateTrackerHandler 的 maybeHandleNetworkAgentMessage 接口中,它被 NetworkStateTrackerHandler 的 handleMessage 调用处理可能的一些消息:
public void handleMessage(Message msg) {
if (!maybeHandleAsyncChannelMessage(msg)
&& !maybeHandleNetworkMonitorMessage(msg)
&& !maybeHandleNetworkAgentInfoMessage(msg)) {
maybeHandleNetworkAgentMessage(msg);
}
}
而 NetworkStateTrackerHandler 作为内部类,继承了 Handler 类,其在 ConnectivityService 类中的对象 mTrackerHandler 在类构造过程中创建,其使用有两个方面:
①:在 handleRegisterNetworkProvider 过程中作为 SrcHandler 来处理 AsyncChannel 的消息,用于与 NetworkProvider 通信的消息处理。而 handleRegisterNetworkProvider 其调用则在 registerNetworkProvider 中进行 EVENT_REGISTER_NETWORK_PROVIDER 消息发送之后,在内部类 InternalHandler 的 handleMessage 处理过程中调用处理。
WiFi 对应的 NetworkProvider 的注册
在 WifiServiceImpl 的 handleBootCompleted 处理过程中调用了 ClientModeImpl 的 handleBootCompleted 接口,在其中执行了 sendMessage 操作将 CMD_BOOT_COMPLETED 发给自己,而其处理在 DefaultState 中:
case CMD_BOOT_COMPLETED:
// get other services that we need to manage
getAdditionalWifiServiceInterfaces();
registerNetworkFactory();
mSarManager.handleBootCompleted();
break;
这里面执行了 registerNetworkFactory:
void registerNetworkFactory() {
if (!checkAndSetConnectivityInstance()) return;
mNetworkFactory.register();
mUntrustedNetworkFactory.register();
}
而 mNetworkFactory 为 WifiNetworkFactory 类对象,继承了 NetworkFactory 类,其 register 接口如下:
/* Registers this NetworkFactory with the system. May only be called once per factory. */
public void register() {
if (mProvider != null) {
throw new IllegalStateException("A NetworkFactory must only be registered once");
}
if (DBG) log("Registering NetworkFactory");
mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) {
@Override
public void onNetworkRequested(@NonNull NetworkRequest request, int score,
int servingProviderId) {
handleAddRequest(request, score, servingProviderId);
}
@Override
public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
handleRemoveRequest(request);
}
};
((ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider);
}
这里创建了 NetworkProvider 对象 mProvider 主要实现了网络请求的调用接口,然后通过 CONNECTIVITY_SERVICE 的 client 应用(ConnectivityManager)调用服务接口 registerNetworkProvider 将其注册到 ConnectivityService 中。
② 在 handleRegisterNetworkAgent 过程中作为 SrcHandler 来处理 AsyncChannel 的消息,用于与 NetworkAgent 通信的消息处理。
那么什么时候调用 registerNetworkAgent 呢?
可以看到直接的调用就是在 ConnectivityManager 中,它作为 ConnectivityService 的客户端类进行服务调用,实际动作发生在 NetworkAgent 类中的 register 接口中:
/**
* 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);
mNetwork = cm.registerNetworkAgent(new Messenger(mHandler),
new NetworkInfo(mInitialConfiguration.info),
mInitialConfiguration.properties, mInitialConfiguration.capabilities,
mInitialConfiguration.score, mInitialConfiguration.config, providerId);
mInitialConfiguration = null; // All this memory can now be GC'd
}
return mNetwork;
}
在 ClientModeImpl 中内部类 WifiNetworkAgent 继承了 NetworkAgent 类,register 接口的调用发生在 WiFiNetworkAgent 的构造过程中:
WifiNetworkAgent(Context c, Looper l, String tag, NetworkCapabilities nc, LinkProperties lp,
int score, NetworkAgentConfig config, NetworkProvider provider) {
super(c, l, tag, nc, lp, score, config, provider);
register();
}
而 WiFiNetworkAgent 的创建发生在 ClientModeImpl 内部类 L2ConnectedState 的 enter 过程中,在 WiFi 连接建立进入 L2ConnectedState 时建立了 L2 网络连接,开始进行创建 NetworkAgent 用于维护连接状态。
因而此时我们回到开始的讨论,因此对应的消息 EVENT_NETWORK_PROPERTIES_CHANGED 就是在 ClientModeImpl 发出的:
private void updateLinkProperties(LinkProperties newLp) {
if (mVerboseLoggingEnabled) {
log("Link configuration changed for netId: " + mLastNetworkId
+ " old: " + mLinkProperties + " new: " + newLp);
}
// We own this instance of LinkProperties because IpClient passes us a copy.
mLinkProperties = newLp;
if (mNetworkAgent != null) {
mNetworkAgent.sendLinkProperties(mLinkProperties);
}
if (mNetworkAgentState == DetailedState.CONNECTED) {
// If anything has changed and we're already connected, send out a notification.
// TODO: Update all callers to use NetworkCallbacks and delete this.
sendLinkConfigurationChangedBroadcast();
}
if (mVerboseLoggingEnabled) {
StringBuilder sb = new StringBuilder();
sb.append("updateLinkProperties nid: " + mLastNetworkId);
sb.append(" state: " + mNetworkAgentState);
if (mLinkProperties != null) {
sb.append(" ");
sb.append(getLinkPropertiesSummary(mLinkProperties));
}
logd(sb.toString());
}
}
这里调用了 NetworkAgent 类对象 mNetworkAgent 的 sendLinkProperties 进行操作:
private void queueOrSendMessage(int what, Object obj) {
queueOrSendMessage(what, 0, 0, obj);
}
private void queueOrSendMessage(int what, int arg1, int arg2) {
queueOrSendMessage(what, arg1, arg2, null);
}
private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) {
Message msg = Message.obtain();
msg.what = what;
msg.arg1 = arg1;
msg.arg2 = arg2;
msg.obj = obj;
queueOrSendMessage(msg);
}
private void queueOrSendMessage(Message msg) {
synchronized (mPreConnectedQueue) {
if (mAsyncChannel != null) {
mAsyncChannel.sendMessage(msg);
} else {
mPreConnectedQueue.add(msg);
}
}
}
/**
* Must be called by the agent when the network's {@link LinkProperties} change.
* @param linkProperties the new LinkProperties.
*/
public final void sendLinkProperties(@NonNull LinkProperties linkProperties) {
Objects.requireNonNull(linkProperties);
queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties));
}
如上最终是调用了 mAsyncChannel 的 sendMessage 将消息发送给另一端。这里 AsyncChannel 是在 NetworkAgentHandler 中创建,其在 NetworkAgent 初始化的时候创建,在 register 中作为参数创建了 Messenger 对象,向 CONNECTIVITY_SERVICE 注册网络代理 registerNetworkAgent。
再看 ClientModeImpl 中的 updateLinkProperties 接口调用,发生在 DefaultState 中处理 CMD_UPDATE_LINKPROPERTIES 消息过程中,该消息在内部类 IpClientCallbacksImpl 中的回调中发出,实际上有两个回调接口:
- onProvisioningSuccess:
- onLinkPropertiesChange:在 IpClient 中 dispatchCallback 调用了 mCallback 的 onLinkPropertiesChange 接口,在 IpClient 创建过程中通过 callback 参数进行封装获得,而在 ClientModeImpl 的 ConnectModeState 的 enter 过程中调用了 setupClientMode 接口在其中创建了 IpClientCallbacksImpl 对象,它继承了 IpClientCallbacks 类,并将其通过 mFacade.makeIpClient 调用,从而调用了 IpClientUtil.makeIpClient 接口,进而调用到 NetworkStackClient 类的 makeIpClient 接口创建了对应的 IpClient 对象;
在 IpClient 中 dispatchCallback 接口调用的地方主要为 RunningState 中的 processMessage 过程,在如下情境下会进行 DhcpClient.CMD_POST_DHCP_ACTION 消息的处理:
- initial address acquisition succeeds,
- renew succeeds or is NAK'd,
- rebind succeeds or is NAK'd, or
- the lease expires, or
- the IPv6-only preferred option is enabled and entering Ipv6OnlyWaitState.
而其中调用了 IpClient 的 handleIPv4Success 接口,里面调用了 dispatchCallback 方法;
另外这里也会处理 DhcpClient.CMD_CONFIGURE_LINKADDRESS 消息,调用 dispatchCallback 接口,不过处理的消息是 PROV_CHANGE_LOST_PROVISIONING;
回过头来看 DhcpClient.CMD_POST_DHCP_ACTION 消息,在 DhcpClient 的 notifySuccess 中会调用其 mController 对象也就是 IpClient 状态机的 sendMessage 接口发送该消息,它的调用者为 ConfiguringInterfaceState 的 enter 接口或者是 DhcpReacquiringState 的 receivePacket 接口,都表示获取到了对应的地址信息。