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

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


之前的几篇文章讲述了Wifi启动、扫描、连接等流程,也简单介绍了网络模块与ConnectifyService之间通信、更新网络的基本实现。现在,就进一步简单介绍下网络更新的具体实现,这里以Ethernet通知CS更新 LinkProperties为例。

EthernetNetworkFactory中通过updateAgent()函数来更新网络状态:
    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);
        }
    }
调用NetworkAgent的send类型方法:
    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));
    }
通过AsyncChannel向CS中的NetworkStateTrackerHandler发送消息,直接看处理实现:
                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;
                }
NetworkAgentInfo可以看做是一个数据类,它内部维护了当前网络的NetworkInfo、LinkProperties等对象。CS中维护了一个HashMap对象,以mMessenger为key,以NetworkAgentInfo对象为value,保存了各个网络模块的网络配置信息。随之调用updateLinkProperties():
   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);
        }
    }
之前一步已经将需要更新的LLinkProperties对象保存到了参数1中,参数2是旧的LLinkProperties配置信息;更新的过程会比较这两个对象。这里主要看3个处理过程:

  1.  updateInterfaces():更新interface
  2. updateRoutes():更新路由表
  3. 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);
            }
        }
    }
CompareResult泛型类是LinkProperties的一个内部类:
    /**
     * @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;
        }
    }
它维护了两个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的更新:
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();
    }
路由更新的实现跟updateInterfaces()类似。
    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();
        }
    }
先从newLp中获取到DNS地址的集合,再将该DNS地址集合设置到Netd中。从代码中发现,这里还可能会将DNS地址保存到一些系统属性中。
到这里,ConnectifyService基本的网络更新流程就结束了。




  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值