Android5.1网络切换策略分析

最近在在5.1移植了以太网过来,移植的过程并没有什么大问题,修改了框架上的代以及添加了Settings代码,以太网调试就基本完工了,后面只是修改下布局即可。但是网络切换策略就有所变化了,就不得不重新认识5.1的网络切换策略了。
在android4.4上,想实现以太网为优先级最高(意思是以太网打开了,WIFI就无法打开),方法很简单,只需要在default.xml和ConnectivityServicet修改就好了。但在5.1系统上就做了新的调整,具体改动的原因不明,他是依靠网络评分的大小来确定谁的优先级高,废话不多说,以以太网为例子,进行追踪。

1、frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetServiceImpl

  public EthernetServiceImpl(Context context) {
        mContext = context;
        Log.i(TAG, "Creating EthernetConfigStore");
        mEthernetConfigStore = new EthernetConfigStore();
        mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations();

        Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration);

        mTracker = new EthernetNetworkFactory(mListeners); //创建本地的网络工厂
     mTracker.setContext(context); //add by peng
   }

2、frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetNetworkFactory

 EthernetNetworkFactory(RemoteCallbackList listeners) {
        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
        mLinkProperties = new LinkProperties();
        initNetworkCapabilities(); //初始化网络参数,比如,上下行速度、传输类型等
        mListeners = listeners;
    }
    //我们看看这个类的start函数
     public synchronized void start(Context context, Handler target) {
        // The services we use.
        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
        mNMService = INetworkManagementService.Stub.asInterface(b);
        mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE); //获取服务

        // Interface match regex.
        mIfaceMatch = context.getResources().getString(
                com.android.internal.R.string.config_ethernet_iface_regex);

        // Create and register our NetworkFactory.
        mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper());
        mFactory.setCapabilityFilter(mNetworkCapabilities); //设置网络参数
        **mFactory.setScoreFilter(-1);** // 这个就是设置网络评分,但是这为-1,因为这是初始化,等有网卡接入,讲评分拉高就行,后面会讲述
        mFactory.register();//注册
        //再来看看当网卡接入的时候做了什么

 private void updateInterfaceState(String iface, boolean up) {
        if (!mIface.equals(iface)) {
            return;
        }
        Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down"));

        synchronized(this) {
            mLinkUp = up;
            mNetworkInfo.setIsAvailable(up);
            if (!up) {
                // Tell the agent we're disconnected. It will call disconnect().
                mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
                sendEthernetStateChangedBroadcast(EthernetManager.ETHER_STATE_DISCONNECTED); //add by peng
            }
            updateAgent();//这个是更新数据的,来看看。
            // set our score lower than any network could go
            // so we get dropped.  TODO - just unregister the factory
            // when link goes down.
            //这里就是当发现网卡up的话就设置评分  否则将评分设置成-1.
            mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); //NETWORK_SCORE 就是自己定义的分数,我这里假设定义70
        }
    }
    //看看这个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);//这个就是重点了,看看里面做了什么
        }
    }

3、在深入去看看sendNetworkScore(score)到底做了写什么。

 public void sendNetworkScore(int score) {
        if (score < 0) {
            throw new IllegalArgumentException("Score must be >= 0");
        }
        queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score)); //很明显是发送了一个消息 以及带上了评分发送出去了
    }

4、全局搜索了下,发现这个消息在ConnectivityService处理了。

                case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
                    if (nai == null) {
                        loge("EVENT_NETWORK_SCORE_CHANGED from unknown NetworkAgent");
                        break;
                    }
                    Integer score = (Integer) msg.obj;
                    if (score != null) updateNetworkScore(nai, score.intValue());
                    break;
                }

        private void updateNetworkScore(NetworkAgentInfo nai, int score) {  //更新网络评分
        if (DBG) log("updateNetworkScore for " + nai.name() + " to " + score);
        if (score < 0) {
            loge("updateNetworkScore for " + nai.name() + " got a negative score (" + score +
                    ").  Bumping score to min of 0");
            score = 0;
        }

        final int oldScore = nai.getCurrentScore(); //获取当前网络评分,比如我之前连接的是WIFI,现在要连接以太网,看看这个函数。
        nai.setCurrentScore(score);

        rematchAllNetworksAndRequests(nai, oldScore);

        sendUpdatedScoreToFactories(nai);
    }

4、getCurrentScore();

  private int getCurrentScore(boolean pretendValidated) {
        int score = currentScore;

        ///M: Support for EPDG testing @{
        if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_EPDG)) {
        Log.d(TAG,"[peng add]  Support for EPDG testing,this score --->"+score);
            return score;
        }
        ///@}
        //add by peng  , set ethernet priority highest.
     if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { //这个就是解决WIFI和以太网网络评分的,先跳过。后面在来分析。
        Log.d(TAG,"[peng add]  Support for TRANSPORT_ETHERNET ,this score --->"+score);
            return score;
        }
        if (!everValidated && !pretendValidated){ 
        score -= UNVALIDATED_SCORE_PENALTY;
        Log.d(TAG,"[peng add]  everValidated and pretendValidated is false,this score --->"+score);
        }
        if (score < 0) score = 0;

        if (networkMisc.explicitlySelected){    
        score = EXPLICITLY_SELECTED_NETWORK_SCORE;  //从log看 WIFI的默认评分是60,随着信号等级加强评分会增加,同时也会减,具体看WIFI的代码吧!这里无论是以太网还是WIFI都会走这个判断,也就是WIFI和以太网的评分都走了100,那么系统又怎么选择了打开谁呢?
        Log.d(TAG,"[peng add]  networkMisc.explicitlySelected,this score full--->"+score);
            }

        return score;
    }

5、网络切换,主要看ConnectivityService的rematchNetworkAndRequests方法。

                    …………
                    if (VDBG) {
                    log("currentScore = " +
                            (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
                            ", newScore = " + newNetwork.getCurrentScore());
                }
                if (currentNetwork == null ||
                        currentNetwork.getCurrentScore() <= newNetwork.getCurrentScore()) { //当连接的网络评分小于或等于新的连接网络评分,那么就remove当前网络,连接新的网络。  也就可以分析出,只要是后者连的,优先级就最高。
                    if (currentNetwork != null) {
                        if (DBG) log("   accepting network in place of " + currentNetwork.name());
                        currentNetwork.networkRequests.remove(nri.request.requestId);
                        currentNetwork.networkLingered.add(nri.request);
                        affectedNetworks.add(currentNetwork);
                    } else {
                        if (DBG) log("   accepting network in place of null");
                    }
                    …………

6、如何设置以太网优先级最高?
将EthernetNetworkFactory的以太网评分增加
private static final int NETWORK_SCORE = 110; //大于100即可,因为WIFI最大的评分是100

在NetworkAgentInfo的getCurrentScore方法里添加以太网的评分,保证不被修改
    //add by peng  , set ethernet priority highest.
 if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
    Log.d(TAG,"[peng add]  Support for TRANSPORT_ETHERNET ,this score --->"+score);
        return score;
    }

“`
这样就可以避免WIFI和以太网同时连接了。具体问题具体分析,以上是个人观点,如果解释的不对,请多多包含。

你可能感兴趣的:(Android底层)