Android -- ConnectifyService网络更新流程简介

Android -- ConnectifyService网络更新流程简介

转自http://blog.csdn.net/csdn_of_coder/article/details/51959561
之前的几篇文章讲述了Wifi启动、扫描、连接等流程,也简单介绍了网络模块与ConnectifyService之间通信、更新网络的基本实现。现在,就进一步简单介绍下网络更新的具体实现,这里以Ethernet通知CS更新 LinkProperties为例。
EthernetNetworkFactory中通过updateAgent()函数来更新网络状态:
  1. public void updateAgent() {  
  2.     synchronized (EthernetNetworkFactory.this) {  
  3.         if (mNetworkAgent == nullreturn;  
  4.         if (DBG) {  
  5.             Log.i(TAG, "Updating mNetworkAgent with: " +  
  6.                   mNetworkCapabilities + ", " +  
  7.                   mNetworkInfo + ", " +  
  8.                   mLinkProperties);  
  9.         }  
  10.         mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);  
  11.         mNetworkAgent.sendNetworkInfo(mNetworkInfo);  
  12.         mNetworkAgent.sendLinkProperties(mLinkProperties);  
  13.         // never set the network score below 0.  
  14.         mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);  
  15.     }  
  16. }  
调用NetworkAgent的send类型方法:
  1. private void queueOrSendMessage(int what, Object obj) {  
  2.     synchronized (mPreConnectedQueue) {  
  3.         if (mAsyncChannel != null) {  
  4.             mAsyncChannel.sendMessage(what, obj);//mDstMessenger指向CS中的NetworkStateTrackerHandler,mSrcMessenger指向当前NetworkAgent对象.  
  5.         } else {  
  6.             Message msg = Message.obtain();  
  7.             msg.what = what;  
  8.             msg.obj = obj;  
  9.             mPreConnectedQueue.add(msg);  
  10.         }  
  11.     }  
  12. }  
  13.   
  14. /** 
  15.  * Called by the bearer code when it has new LinkProperties data. 
  16.  */  
  17. public void sendLinkProperties(LinkProperties linkProperties) {  
  18.     queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties));  
  19. }  
通过AsyncChannel向CS中的NetworkStateTrackerHandler发送消息,直接看处理实现:
  1. case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {  
  2.     NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);  
  3.     if (nai == null) {  
  4.         loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED");  
  5.     } else {  
  6.         if (VDBG) {  
  7.             log("Update of LinkProperties for " + nai.name() +  
  8.                     "; created=" + nai.created);  
  9.         }  
  10.         LinkProperties oldLp = nai.linkProperties;  
  11.         synchronized (nai) {  
  12.             nai.linkProperties = (LinkProperties)msg.obj;  
  13.         }  
  14.         if (nai.created) updateLinkProperties(nai, oldLp);  
  15.     }  
  16.     break;  
  17. }  
NetworkAgentInfo可以看做是一个数据类,它内部维护了当前网络的NetworkInfo、LinkProperties等对象。CS中维护了一个HashMap对象,以mMessenger为key,以NetworkAgentInfo对象为value,保存了各个网络模块的网络配置信息。随之调用updateLinkProperties():
  1.    private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {  
  2.         LinkProperties newLp = networkAgent.linkProperties;  
  3.         int netId = networkAgent.network.netId;  
  4.   
  5.         // The NetworkAgentInfo does not know whether clatd is running on its network or not. Before  
  6.         // we do anything else, make sure its LinkProperties are accurate.  
  7.         if (networkAgent.clatd != null) {  
  8.             networkAgent.clatd.fixupLinkProperties(oldLp);  
  9.         }  
  10.   
  11.         updateInterfaces(newLp, oldLp, netId);  
  12.         updateMtu(newLp, oldLp);  
  13.         // TODO - figure out what to do for clat  
  14. //        for (LinkProperties lp : newLp.getStackedLinks()) {  
  15. //            updateMtu(lp, null);  
  16. //        }  
  17.         updateTcpBufferSizes(networkAgent);  
  18.   
  19.         // TODO: deprecate and remove mDefaultDns when we can do so safely. See http://b/18327075  
  20.         // In L, we used it only when the network had Internet access but provided no DNS servers.  
  21.         // For now, just disable it, and if disabling it doesn't break things, remove it.  
  22.         // final boolean useDefaultDns = networkAgent.networkCapabilities.hasCapability(  
  23.         //        NET_CAPABILITY_INTERNET);  
  24.         final boolean useDefaultDns = false;  
  25.         final boolean flushDns = updateRoutes(newLp, oldLp, netId);  
  26.         updateDnses(newLp, oldLp, netId, flushDns, useDefaultDns);  
  27.   
  28.         updateClat(newLp, oldLp, networkAgent);  
  29.         if (isDefaultNetwork(networkAgent)) {  
  30.             handleApplyDefaultProxy(newLp.getHttpProxy());  
  31.         } else {  
  32.             updateProxy(newLp, oldLp, networkAgent);  
  33.         }  
  34.         // TODO - move this check to cover the whole function  
  35.         if (!Objects.equals(newLp, oldLp)) {  
  36.             notifyIfacesChanged();  
  37.             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);  
  38.         }  
  39.     }  
之前一步已经将需要更新的LLinkProperties对象保存到了参数1中,参数2是旧的LLinkProperties配置信息;更新的过程会比较这两个对象。这里主要看3个处理过程:
  1.  updateInterfaces():更新interface
  2. updateRoutes():更新路由表
  3. updateDnses():更新DNS
  1. private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId) {  
  2.     CompareResult<String> interfaceDiff = new CompareResult<String>();  
  3.     if (oldLp != null) {  
  4.         interfaceDiff = oldLp.compareAllInterfaceNames(newLp);  
  5.     } else if (newLp != null) {  
  6.         interfaceDiff.added = newLp.getAllInterfaceNames();  
  7.     }  
  8.     for (String iface : interfaceDiff.added) {  
  9.         try {  
  10.             if (DBG) log("Adding iface " + iface + " to network " + netId);  
  11.             mNetd.addInterfaceToNetwork(iface, netId);  
  12.         } catch (Exception e) {  
  13.             loge("Exception adding interface: " + e);  
  14.         }  
  15.     }  
  16.     for (String iface : interfaceDiff.removed) {  
  17.         try {  
  18.             if (DBG) log("Removing iface " + iface + " from network " + netId);  
  19.             mNetd.removeInterfaceFromNetwork(iface, netId);  
  20.         } catch (Exception e) {  
  21.             loge("Exception removing interface: " + e);  
  22.         }  
  23.     }  
  24. }  
CompareResult泛型类是LinkProperties的一个内部类:
  1. /** 
  2.  * @hide 
  3.  */  
  4. public static class CompareResult<T> {  
  5.     public List<T> removed = new ArrayList<T>();  
  6.     public List<T> added = new ArrayList<T>();  
  7.   
  8.     @Override  
  9.     public String toString() {  
  10.         String retVal = "removed=[";  
  11.         for (T addr : removed) retVal += addr.toString() + ",";  
  12.         retVal += "] added=[";  
  13.         for (T addr : added) retVal += addr.toString() + ",";  
  14.         retVal += "]";  
  15.         return retVal;  
  16.     }  
  17. }  
它维护了两个ArrayList集合:added和removed。当oldLp不为空时,就会调用方法得到一个CompareResult对象,此时added和removed集合的内容为:


removed是要删除的部分,added是要添加更新的部分;自行看下compareAllInterfaceNames()的实现即可。
接着是分别遍历removed和added集合,调用NetworkManagementService内部的方法,更新interface。
NetworkManagementService负责跟底层的Netd进行通信。Netd 就是Network Daemon 的缩写,表示Network守护进程。
Netd负责一些涉及网络的配置,操作,管理,查询等相关的功能实现,比如,例如带宽控制(Bandwidth),流量统计,带宽控制,网络地址转换(NAT),个人局域网(pan),PPP链接,soft-ap,共享上网(Tether),配置路由表,interface配置管理,等等……
同理,updateRoutes()、updateDnses()也是通过NetworkManagementService分别进行route和DNS的更新:
  1. private boolean updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {  
  2.         CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();  
  3.         if (oldLp != null) {  
  4.             routeDiff = oldLp.compareAllRoutes(newLp);  
  5.         } else if (newLp != null) {  
  6.             routeDiff.added = newLp.getAllRoutes();  
  7.         }  
  8.   
  9.         // add routes before removing old in case it helps with continuous connectivity  
  10.   
  11.         // do this twice, adding non-nexthop routes first, then routes they are dependent on  
  12.         for (RouteInfo route : routeDiff.added) {  
  13.             if (route.hasGateway()) continue;  
  14.             if (DBG) log("Adding Route [" + route + "] to network " + netId);  
  15.             try {  
  16.                 mNetd.addRoute(netId, route);  
  17.             } catch (Exception e) {  
  18.                 if ((route.getDestination().getAddress() instanceof Inet4Address) || VDBG) {  
  19.                     loge("Exception in addRoute for non-gateway: " + e);  
  20.                 }  
  21.             }  
  22.         }  
  23.         for (RouteInfo route : routeDiff.added) {  
  24.             if (route.hasGateway() == falsecontinue;  
  25.             if (DBG) log("Adding Route [" + route + "] to network " + netId);  
  26.             try {  
  27.                 mNetd.addRoute(netId, route);  
  28.             } catch (Exception e) {  
  29.                 if ((route.getGateway() instanceof Inet4Address) || VDBG) {  
  30.                     loge("Exception in addRoute for gateway: " + e);  
  31.                 }  
  32.             }  
  33.         }  
  34.   
  35.         for (RouteInfo route : routeDiff.removed) {  
  36.             if (DBG) log("Removing Route [" + route + "] from network " + netId);  
  37.             try {  
  38.                 mNetd.removeRoute(netId, route);  
  39.             } catch (Exception e) {  
  40.                 loge("Exception in removeRoute: " + e);  
  41.             }  
  42.         }  
  43.         return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty();  
  44.     }  
路由更新的实现跟updateInterfaces()类似。
  1. private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId,  
  2.                          boolean flush, boolean useDefaultDns) {  
  3.     if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {  
  4.         Collection<InetAddress> dnses = newLp.getDnsServers();  
  5.         if (dnses.size() == 0 && mDefaultDns != null && useDefaultDns) {  
  6.             dnses = new ArrayList();  
  7.             dnses.add(mDefaultDns);  
  8.             if (DBG) {  
  9.                 loge("no dns provided for netId " + netId + ", so using defaults");  
  10.             }  
  11.         }  
  12.         if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);  
  13.         try {  
  14.             mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),  
  15.                 newLp.getDomains());  
  16.         } catch (Exception e) {  
  17.             loge("Exception in setDnsServersForNetwork: " + e);  
  18.         }  
  19.         final NetworkAgentInfo defaultNai = getDefaultNetwork();  
  20.         if (defaultNai != null && defaultNai.network.netId == netId) {  
  21.             setDefaultDnsSystemProperties(dnses);  
  22.         }  
  23.         flushVmDnsCache();  
  24.     } else if (flush) {  
  25.         try {  
  26.             mNetd.flushNetworkDnsCache(netId);  
  27.         } catch (Exception e) {  
  28.             loge("Exception in flushNetworkDnsCache: " + e);  
  29.         }  
  30.         flushVmDnsCache();  
  31.     }  
  32. }  
先从newLp中获取到DNS地址的集合,再将该DNS地址集合设置到Netd中。从代码中发现,这里还可能会将DNS地址保存到一些系统属性中。
到这里,ConnectifyService基本的网络更新流程就结束了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值