Android -- ConnectifyService网络更新流程简介
转自http://blog.csdn.net/csdn_of_coder/article/details/51959561
之前的几篇文章讲述了Wifi启动、扫描、连接等流程,也简单介绍了网络模块与ConnectifyService之间通信、更新网络的基本实现。现在,就进一步简单介绍下网络更新的具体实现,这里以Ethernet通知CS更新 LinkProperties为例。
EthernetNetworkFactory中通过updateAgent()函数来更新网络状态:
调用NetworkAgent的send类型方法:
通过AsyncChannel向CS中的NetworkStateTrackerHandler发送消息,直接看处理实现:
NetworkAgentInfo可以看做是一个数据类,它内部维护了当前网络的NetworkInfo、LinkProperties等对象。CS中维护了一个HashMap对象,以mMessenger为key,以NetworkAgentInfo对象为value,保存了各个网络模块的网络配置信息。随之调用updateLinkProperties():
之前一步已经将需要更新的LLinkProperties对象保存到了参数1中,参数2是旧的LLinkProperties配置信息;更新的过程会比较这两个对象。这里主要看3个处理过程:
- public void updateAgent() {
- synchronized (EthernetNetworkFactory.this) {
- if (mNetworkAgent == null) return;
- if (DBG) {
- Log.i(TAG, "Updating mNetworkAgent with: " +
- mNetworkCapabilities + ", " +
- mNetworkInfo + ", " +
- mLinkProperties);
- }
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
- mNetworkAgent.sendLinkProperties(mLinkProperties);
- // never set the network score below 0.
- mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);
- }
- }
- private void queueOrSendMessage(int what, Object obj) {
- synchronized (mPreConnectedQueue) {
- if (mAsyncChannel != null) {
- mAsyncChannel.sendMessage(what, obj);//mDstMessenger指向CS中的NetworkStateTrackerHandler,mSrcMessenger指向当前NetworkAgent对象.
- } else {
- Message msg = Message.obtain();
- msg.what = what;
- msg.obj = obj;
- mPreConnectedQueue.add(msg);
- }
- }
- }
- /**
- * Called by the bearer code when it has new LinkProperties data.
- */
- public void sendLinkProperties(LinkProperties linkProperties) {
- queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties));
- }
- case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
- NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
- if (nai == null) {
- loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED");
- } else {
- if (VDBG) {
- log("Update of LinkProperties for " + nai.name() +
- "; created=" + nai.created);
- }
- LinkProperties oldLp = nai.linkProperties;
- synchronized (nai) {
- nai.linkProperties = (LinkProperties)msg.obj;
- }
- if (nai.created) updateLinkProperties(nai, oldLp);
- }
- break;
- }
- private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
- LinkProperties newLp = networkAgent.linkProperties;
- int netId = networkAgent.network.netId;
- // The NetworkAgentInfo does not know whether clatd is running on its network or not. Before
- // we do anything else, make sure its LinkProperties are accurate.
- if (networkAgent.clatd != null) {
- networkAgent.clatd.fixupLinkProperties(oldLp);
- }
- updateInterfaces(newLp, oldLp, netId);
- updateMtu(newLp, oldLp);
- // TODO - figure out what to do for clat
- // for (LinkProperties lp : newLp.getStackedLinks()) {
- // updateMtu(lp, null);
- // }
- updateTcpBufferSizes(networkAgent);
- // TODO: deprecate and remove mDefaultDns when we can do so safely. See http://b/18327075
- // In L, we used it only when the network had Internet access but provided no DNS servers.
- // For now, just disable it, and if disabling it doesn't break things, remove it.
- // final boolean useDefaultDns = networkAgent.networkCapabilities.hasCapability(
- // NET_CAPABILITY_INTERNET);
- final boolean useDefaultDns = false;
- final boolean flushDns = updateRoutes(newLp, oldLp, netId);
- updateDnses(newLp, oldLp, netId, flushDns, useDefaultDns);
- updateClat(newLp, oldLp, networkAgent);
- if (isDefaultNetwork(networkAgent)) {
- handleApplyDefaultProxy(newLp.getHttpProxy());
- } else {
- updateProxy(newLp, oldLp, networkAgent);
- }
- // TODO - move this check to cover the whole function
- if (!Objects.equals(newLp, oldLp)) {
- notifyIfacesChanged();
- notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
- }
- }
- updateInterfaces():更新interface
- updateRoutes():更新路由表
- updateDnses():更新DNS
- private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId) {
- CompareResult<String> interfaceDiff = new CompareResult<String>();
- if (oldLp != null) {
- interfaceDiff = oldLp.compareAllInterfaceNames(newLp);
- } else if (newLp != null) {
- interfaceDiff.added = newLp.getAllInterfaceNames();
- }
- for (String iface : interfaceDiff.added) {
- try {
- if (DBG) log("Adding iface " + iface + " to network " + netId);
- mNetd.addInterfaceToNetwork(iface, netId);
- } catch (Exception e) {
- loge("Exception adding interface: " + e);
- }
- }
- for (String iface : interfaceDiff.removed) {
- try {
- if (DBG) log("Removing iface " + iface + " from network " + netId);
- mNetd.removeInterfaceFromNetwork(iface, netId);
- } catch (Exception e) {
- loge("Exception removing interface: " + e);
- }
- }
- }
- /**
- * @hide
- */
- public static class CompareResult<T> {
- public List<T> removed = new ArrayList<T>();
- public List<T> added = new ArrayList<T>();
- @Override
- public String toString() {
- String retVal = "removed=[";
- for (T addr : removed) retVal += addr.toString() + ",";
- retVal += "] added=[";
- for (T addr : added) retVal += addr.toString() + ",";
- retVal += "]";
- return retVal;
- }
- }
接着是分别遍历removed和added集合,调用NetworkManagementService内部的方法,更新interface。
NetworkManagementService负责跟底层的Netd进行通信。Netd 就是Network Daemon 的缩写,表示Network守护进程。
Netd负责一些涉及网络的配置,操作,管理,查询等相关的功能实现,比如,例如带宽控制(Bandwidth),流量统计,带宽控制,网络地址转换(NAT),个人局域网(pan),PPP链接,soft-ap,共享上网(Tether),配置路由表,interface配置管理,等等……
Netd负责一些涉及网络的配置,操作,管理,查询等相关的功能实现,比如,例如带宽控制(Bandwidth),流量统计,带宽控制,网络地址转换(NAT),个人局域网(pan),PPP链接,soft-ap,共享上网(Tether),配置路由表,interface配置管理,等等……
同理,updateRoutes()、updateDnses()也是通过NetworkManagementService分别进行route和DNS的更新:
路由更新的实现跟updateInterfaces()类似。
先从newLp中获取到DNS地址的集合,再将该DNS地址集合设置到Netd中。从代码中发现,这里还可能会将DNS地址保存到一些系统属性中。
- private boolean updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
- CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
- if (oldLp != null) {
- routeDiff = oldLp.compareAllRoutes(newLp);
- } else if (newLp != null) {
- routeDiff.added = newLp.getAllRoutes();
- }
- // add routes before removing old in case it helps with continuous connectivity
- // do this twice, adding non-nexthop routes first, then routes they are dependent on
- for (RouteInfo route : routeDiff.added) {
- if (route.hasGateway()) continue;
- if (DBG) log("Adding Route [" + route + "] to network " + netId);
- try {
- mNetd.addRoute(netId, route);
- } catch (Exception e) {
- if ((route.getDestination().getAddress() instanceof Inet4Address) || VDBG) {
- loge("Exception in addRoute for non-gateway: " + e);
- }
- }
- }
- for (RouteInfo route : routeDiff.added) {
- if (route.hasGateway() == false) continue;
- if (DBG) log("Adding Route [" + route + "] to network " + netId);
- try {
- mNetd.addRoute(netId, route);
- } catch (Exception e) {
- if ((route.getGateway() instanceof Inet4Address) || VDBG) {
- loge("Exception in addRoute for gateway: " + e);
- }
- }
- }
- for (RouteInfo route : routeDiff.removed) {
- if (DBG) log("Removing Route [" + route + "] from network " + netId);
- try {
- mNetd.removeRoute(netId, route);
- } catch (Exception e) {
- loge("Exception in removeRoute: " + e);
- }
- }
- return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty();
- }
- private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId,
- boolean flush, boolean useDefaultDns) {
- if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
- Collection<InetAddress> dnses = newLp.getDnsServers();
- if (dnses.size() == 0 && mDefaultDns != null && useDefaultDns) {
- dnses = new ArrayList();
- dnses.add(mDefaultDns);
- if (DBG) {
- loge("no dns provided for netId " + netId + ", so using defaults");
- }
- }
- if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);
- try {
- mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),
- newLp.getDomains());
- } catch (Exception e) {
- loge("Exception in setDnsServersForNetwork: " + e);
- }
- final NetworkAgentInfo defaultNai = getDefaultNetwork();
- if (defaultNai != null && defaultNai.network.netId == netId) {
- setDefaultDnsSystemProperties(dnses);
- }
- flushVmDnsCache();
- } else if (flush) {
- try {
- mNetd.flushNetworkDnsCache(netId);
- } catch (Exception e) {
- loge("Exception in flushNetworkDnsCache: " + e);
- }
- flushVmDnsCache();
- }
- }
到这里,ConnectifyService基本的网络更新流程就结束了。