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<IEthernetServiceListener> 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和以太網同時連接了。具體問題具體分析,以上是個人觀點,如果解釋的不對,請多多包含。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章